使用linq查找包含名称列表的xml元素列表(并删除它们)

时间:2015-12-03 16:30:23

标签: c# xml linq

我有以下XML

<itemList>
  <Item>
    <shipAddress></shipAddress>
    <shipMethod></shipMethod>
    <rate>50.00</rate>
    <custom>
        <custcol_1>55</custcol_1>
        <custcol_2>60</custcol_2>
    </custom>
    <special>
       <special1>A</special1>
    </special>
  </Item>
  <Item>
     <shipAddress></shipAddress>
     <rate>50.00</rate>
     <custom>
        <custcol_1>7889</custcol_1>
        <custcol_2>754</custcol_2>
     </custom>
 </Item>  
</itemList>

我要做的是收集<custom><special>所有节点的列表,因为我想删除它们。

我尝试用以下方法做到这一点,但它没有得到任何节点:

nodesToRemove = xeConsolItm.Elements()
    .Where(itm =>
    (
        itm.Element("custom") != null &&
        itm.Element("special") != null &&
        itm.Element("other") != null
    ))
    .ToList();


foreach (var xElement in nodesToRemove)
{
    nodesToRemove.Remove();
}

我也尝试使用||,但这也不起作用。在这两种情况下,nodesToRemove最终都为空。

我想知道一种方法。 我已经能够一次删除每个,但是当我尝试将3合并在一起时,我没有运气。是一次只做一次的最好方法吗?

3 个答案:

答案 0 :(得分:2)

您应该使用Descendants()代替Elements()来获取任何深度的元素。

此外,您应该使用Name属性来获取元素的名称。

var nodesToRemove = xeConsolItm.Descendants()
    .Where(itm =>
        itm.Name == "custom" || itm.Name == "special" || itm.Name == "other")
    .ToList();

此外,您还需要按照评论中的说明修复循环。

foreach (var xElement in nodesToRemove)
{
    xElement.Remove();
}

@CharlesMager建议的更简单的版本是:

xeConsolItm.Descendants()
    .Where(itm =>
        itm.Name == "custom" || itm.Name == "special" || itm.Name == "other").Remove();

答案 1 :(得分:0)

@ YacoubMassad的回答是正确的,会给你预期的结果。根据您现有的语法,这是一种不同的(当然不是那么干净)获得结果的方法:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.elements = [
      {id: 1, name: 'bonjour'},
      {id: 2, name: 'bonsoir'}
    ];
  $scope.text = 'Hello world';
});

app.directive("frameelement", ['$interpolate', function($interpolate) {
  return {
        restrict: 'EA',
        scope: {
            thiselem: '='
        },
        template: '<div ng-bind="getTemplate(thiselem)"></div>',
        link: function(scope, element, attrs) {
            scope.getTemplate = function(thiselem) {
                return $interpolate('<h1>{{thiselem.id}} : {{thiselem.name}} tt</h1>')(scope);
            }
        }
    };
}]);

您当前的代码存在一些问题,即:

  • 您选择的是var nodesToRemove = xeConsolItm.Elements().Nodes() .Where(itm => itm.ToString().Contains("custom") || itm.ToString().Contains("special") || itm.ToString().Contains("other")).ToList(); foreach (var xElement in nodesToRemove) { xElement.Remove(); } ,而不是Elements
  • 您找不到包含Nodes
  • Node
  • 尝试按照评论中提到的"custom" && "special" && "other"代替nodesToRemove.Remove()

您仍然可以从xElement.Remove();选择Elements,但结果会为您提供整个xeConsolItm,而不仅仅是<Item></Item> Element

答案 2 :(得分:0)

我建议创建一个类,然后反序列化/序列化。

通过课程,您可以完全控制并且更容易工作。

using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace YourNameSpace
{
    [XmlRoot(ElementName="Item")]
    public class Item
    {
        [XmlElement(ElementName="shipAddress")]
        public string ShipAddress { get; set; }
        [XmlElement(ElementName="shipMethod")]
        public string ShipMethod { get; set; }
        [XmlElement(ElementName="rate")]
        public string Rate { get; set; }
        [XmlElement(ElementName="custom")]
        public Dictionary<string,int> Custom { get; set; }
        [XmlElement(ElementName="special")]
        public Dictionary<string,int>Special { get; set; }
    }

    [XmlRoot(ElementName="itemList")]
    public class ItemList
    {
        [XmlElement(ElementName="Item")]
        public List<Item> Item { get; set; }
    }
}

当属性具有不同的名称时,我使用Dictionary,然后您可以使用LINQ来访问它们。

获取字典的价值:

var valueOfFirstSpecialElement = Special.FirstOrDefault().Value;

使用XmlSerializer序列化/反序列化:

https://msdn.microsoft.com/en-us/library/58a18dwa(v=vs.110).aspx

在您的情况下,如果您不想要自定义和特殊功能,只需从课程中删除属性,并在反序列化后不再使用它们。