您只需要解析该 xmlsnippet 一次(假设它适合内存),然后使用XNamespace来限定正确的 XElement。无需调用RemoveAllnamespaces
它,我猜它的名字所暗示的那样,并且可能以一种可怕的方式这样做。
我使用以下 XML 片段作为示例输入,注意命名空间 a、b 和 c:
var xmlsnippet = @"<root xmlns:a=""https://a.example.com""
xmlns:b=""https://b.example.com""
xmlns:c=""https://c.example.com"">
<child>
<a:leaf>42</a:leaf>
<a:leaf>43</a:leaf>
<a:leaf>44</a:leaf>
<somenode>
<b:sas>4242</b:sas>
<b:sas>4343</b:sas>
</somenode>
<other>
<c:kir>80292</c:kir>
<c:kir>0</c:kir>
</other>
</child>
</root>";
然后使用 Linq 如果您的 Test 类返回一个实例,或者如果找不到元素则返回 null。然后将该 Test 类实例添加到数组列表中。
var arr = new ArrayList();
var xdoc = XDocument.Parse(xmlsnippet);
// add namespaces
var nsa = (XNamespace) "https://a.example.com";
var nsb = (XNamespace) "https://b.example.com";
var nsc = (XNamespace) "https://c.example.com";
var leaf = xdoc.Descendants(nsa + "leaf").
Select(elem => new Test("leaf", elem.Value, 2)).FirstOrDefault();
if (leaf != null) {
arr.Add(leaf);
}
var sas = xdoc.Descendants(nsb + "sas").
Select(elem => new Test("sas", elem.Value, 2)).FirstOrDefault();
if (sas != null) {
arr.Add(sas);
}
var kir = xdoc.
Descendants(nsc + "kir").
Where(ele => ele.Value == "0").
Select(elem => new Test("kir", "90", 2)).
FirstOrDefault();
if (kir != null) {
arr.Add(kir);
}
如果您想坚持使用 XDocument,我希望这是查找这些节点的最有效方法。如果 xml 真的很大,您可能会考虑使用 XMLReader,但这可能仅在内存有问题时才有帮助。
如果你想做一个 LINQ 查询,你可以这样做:
var q = xdoc
.Descendants()
.Where(elem => elem.Name.LocalName == "leaf" ||
elem.Name.LocalName == "sas" ||
elem.Name.LocalName == "kir" && elem.Value == "0" )
.GroupBy(k=> k.Name.LocalName)
.Select(k=>
new Test(
k.Key,
k.Key != "kir"? k.FirstOrDefault().Value: "90",
2)
);
arr.AddRange(q.ToList());
该查询查找所有名为leaf、sas 或kir 的元素,将它们按元素名分组,然后获取每个组中的第一个元素。注意如果元素名是 kir 的额外处理。where 子句和投影都Select
需要处理这个问题。您可能想对此进行性能测试,因为我不确定这会有多有效。
为了完整起见,这里是一个 XmlReader 版本:
var state = FoundElement.NONE;
using(var xe = XmlReader.Create(new StringReader(xmlsnippet)))
while (xe.Read())
{
// if we have not yet found an specific element
if (((state & FoundElement.Leaf) != FoundElement.Leaf) &&
xe.LocalName == "leaf")
{
// add it ... do not change the order of those arguments
arr.Add(new Test(xe.LocalName, xe.ReadElementContentAsString(), 2));
// keep track what we already handled.
state = state | FoundElement.Leaf;
}
if (((state & FoundElement.Sas) != FoundElement.Sas) &&
xe.LocalName == "sas")
{
arr.Add(new Test(xe.LocalName, xe.ReadElementContentAsString(), 2));
state = state | FoundElement.Sas;
}
if (((state & FoundElement.Kir) != FoundElement.Kir) &&
xe.LocalName == "kir")
{
var localName = xe.LocalName; // we need this ...
var cnt = xe.ReadElementContentAsString(); // ... because this moves the reader
if (cnt == "0") {
arr.Add(new Test(localName, "90", 2));
state = state | FoundElement.Kir;
}
}
}
这是具有不同状态的枚举。
[Flags]
enum FoundElement
{
NONE =0,
Leaf = 1,
Sas = 2,
Kir = 4
}