Я запрашиваю веб-сервис в C #, и он возвращает XML, который я проанализировал в 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 only возвращает attr1, а не attr1 через attrN. Какие-либо предложения?

0
Steve Cardella 29 Авг 2017 в 17:02

5 ответов

Лучший ответ

Использовать это:

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();
}
1
PinBack 31 Авг 2017 в 07:55

Просто создайте новый документ с необходимыми атрибутами

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
Fabio 29 Авг 2017 в 14:38

Существуют методы, предназначенные для удаления содержимого 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();
1
Jeff Mercado 29 Авг 2017 в 22:09

Я думаю, вам понадобятся две петли:

// 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
Niklas Wulff 29 Авг 2017 в 14:07

Просто добавьте метод ToArray () в цикл foreach:

foreach (XAttribute attribute in output.Descendants("element").Attributes().ToArray())
{
    if (!Array.Exists<String>(WS_LookupFields, fieldname => attribute.Name == fieldname)) attribute.Remove();
}
0
alobster 29 Авг 2017 в 14:25