2017-08-29 105 views
0

我在C#中查詢web服務,它返回XML,我已經將它解析爲一個XDocument。我刪除返回統計信息的服務電話和留下這樣的事情是一個多餘的節點:C#XDocument刪除不在列表中的屬性

<xml> 
    <element attr1="1" attr2="2" attr3="3" attr4="4" ... attrN="N" /> 
    <element attr1="a" attr2="b" attr3="c" ... attrN="N" /> 
    ... 
    <element attr1="!" attr2="?" attr3=":" attr4="" ... attrN="N /> 
</xml> 

我真的只是在檢索attR2位和attr3感興趣,所以我想刪除所有其他屬性風了這一點:

<xml> 
    <element attr2="2" attr3="3" /> 
    <element attr2="b" attr3="c" /> 
    ... 
    <element attr2="?" attr3=":" /> 
</xml> 

然而,這裏有我使用代碼的相關位,僅能去除attR1位:

String[] WS_LookupFields = "attr2,attr3".Split(','); 
var output = XDocument.Parse(WS_Output_Raw); 
output.Descendants("system").Remove(); //removes query statistics 
foreach (XAttribute attribute in output.Descendants("element").Attributes()) 
{ 
    if (!Array.Exists<String>(WS_LookupFields, fieldname => attribute.Name == fieldname)) attribute.Remove(); 
} 

的問題是,在foreach 只有通過attrN返回attr1而不是attr1。有什麼建議麼?

+0

替換'字符串[] WS_LookupFields = 「attR1位,attR2位」 .Split( ' ');'與 '字符串[] WS_LookupFields = 「attR2位,attr3」 .Split(',');'。請讓我知道如果這可以解決您的問題 –

+0

對不起,這是一個錯字;不適用於實際的代碼。 –

回答

1

使用創建新的文檔這樣的:

var WS_LookupFields = "attr2,attr3".Split(',').ToList(); 
var output = XDocument.Parse(WS_Output_Raw); 
foreach (var loElement in output.Descendants("element")) 
{ 
    //loElement.Attributes() 
    // .Where(item => !WS_LookupFields.Any(name => item.Name == name)) 
    // .ToList() 
    // .ForEach(item => item.Remove()); 
    //UPDATE: Charles Mager 
    loElement.Attributes() 
     .Where(item => !WS_LookupFields.Any(name => item.Name == name)) 
     .Remove(); 
} 

或者:

foreach (var loAttribute in output.Descendants("element").Attributes().ToList()) 
{ 
    if (!WS_LookupFields.Contains(loAttribute.Name.ToString())) 
     loAttribute.Remove(); 
} 
+0

完美。我錯過了對System.Linq的引用,但是一旦我添加了這些代碼,您的代碼就可以很好地工作。 (我想知道爲什麼我沒有在方法列表中看到像Where這樣的東西。) –

+1

我強烈建議不要使用'.ToList().ForEach(..)'(參見[this question](https:/ /stackoverflow.com/questions/7816781/tolist-foreach-in-linq))。令人高興的是,你可以用['.Remove()']替換(https://msdn.microsoft.com/en-us/library/bb343722(v = vs.110).aspx)。 –

+0

@Charles Mager:我沒有意識到foreach的問題。基本上,它的使用不應該是一個問題。但是你是對的,你可以直接從'IEnumerable '調用'Remove'。謝謝 – PinBack

0

我想你會需要兩個循環:

// Loop all descendants 
foreach (var element in output.Descendants("element")) 
{ 
    // for that element, loop all attributes 
    foreach (var attribute in element.Attributes()) 
    { 
    if (!Array.Exists<String>(WS_LookupFields, fieldname => attribute.Name == 
fieldname)) attribute.Remove(); 
    } 
} 
+0

請注意,這是完全未經測試 –

+0

我曾嘗試過,忘了提及。它在輸出中沒有任何區別。 –

0

只是需要的屬性

var required = new HashSet<string> { "attr2", "attr3" }; 

var elements = original.Descendants("element").Select(element => 
{ 
    var attributes = element.Attributes().Where(a => required.Contains(a.Name.LocalName)); 
    return new XElement(element.Name, attributes); 
}); 

var root = new XElement(original.Root.Name, elements); 
var newDocument = new XDocument(original.Declaration, root); 
0

只需添加ToArray的()方法,您的foreach循環:

foreach (XAttribute attribute in output.Descendants("element").Attributes().ToArray()) 
{ 
    if (!Array.Exists<String>(WS_LookupFields, fieldname => attribute.Name == fieldname)) attribute.Remove(); 
} 
1

有旨在消除從樹的XML內容的方法。你已經使用了Element這一個,也使用了屬性。

建立一個查詢來選擇要刪除的屬性,然後刪除它們。

var attrs = new HashSet<string>("attr2,attr3".Split(',')); 
foreach (var e in output.Descendants("element")) 
    e.Attributes().Where(a => !attrs.Contains(a.Name.LocalName)).Remove(); 

// or simply 
output.Descendants("element") 
    .Attributes() 
    .Where(a => !attrs.Contains(a.Name.LocalName)) 
    .Remove();