2017-08-29 63 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();