【问题标题】:C# Removing entire elements from XMLDocument based on list of unwanted attribute valuesC# 根据不需要的属性值列表从 XMLDocument 中删除整个元素
【发布时间】:2014-11-13 21:12:46
【问题描述】:

我有一个 XML 文件,例如

<Bars1>
    <Bar name='0'>245</Bar>
    <Bar name='1'>180</Bar>
    <Bar name='2'>120</Bar>
    <Bar name='3'>60</Bar>
    <Bar name='4'>0</Bar>
</Bars1>
<Bars2>
    <Bar name='0'>25</Bar>
    <Bar name='1'>10</Bar>
    <Bar name='2'>10</Bar>
    <Bar name='3'>6</Bar>
    <Bar name='4'>0</Bar>
</Bars2>
<Gubbins3>
    <Bar name='0'>45</Bar>
    <Bar name='1'>18</Bar>
    <Bar name='2'>12</Bar>
    <Bar name='3'>4</Bar>
    <Bar name='4'>0</Bar>
</Gubbins3>

和一个List&lt;int&gt;notNeededBarNames,包含例如{ 1, 3 }

我已将 XML 文件加载到 XmlDocument xmlDoc 中,并且想要从我的列表中删除属性“name”是整数之一的任何“Bar”元素,无论它可能存在于 XML 中的什么位置。我的示例很小,但实际上文档和列表可能很大。

有没有很好的优雅方法来做到这一点?我可以“蛮力”它,但我不禁觉得可能有更好的方法。

希望你能帮忙!

【问题讨论】:

  • I can "brute force" it 先做吧,然后问一个关于你的代码的具体问题。

标签: c# xpath xmldocument


【解决方案1】:

Linq2Xml 可以让生活更轻松。

var notNeededBarNames = new List<int>() { 1, 3 };
var xDoc = XDocument.Load(filename);

xDoc.Descendants("Bar")
    .Where(bar => notNeededBarNames.Contains( (int)bar.Attribute("name")) )
    .Remove();

var newXml = xDoc.ToString();

【讨论】:

    【解决方案2】:

    对于基于 xpath 的解决方案,您可以选择要删除的节点,如下所示:

    private static void TestXmlBars()
        {
                string s = @"<root>
                                            <Bars1>...</Bars1>
                                            <Bars2>...</Bars2>
                                            <Gubbins3>...</Gubbins3>
                                        </root>";
    
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(s);
    
                List<int> exclude = new List<int>{1,2};
                // create comma-delimited list
                string list = "," + String.Join(",", exclude) + ","; 
                string xpath = String.Format("/root/*/Bar[contains('{0}', concat(',', @name, ','))]", list);
                XmlNodeList nodesToExclude = doc.SelectNodes(xpath);
                foreach (XmlNode node in nodesToExclude)
                {
                        node.ParentNode.RemoveChild(node);
                }
                Console.WriteLine(doc.OuterXml);
        }
    

    (请注意,xpath 1 受到限制,因为它没有“in”功能,因此“contains”解决方法 - 请参阅 XPath 1.0 to find if an element's value is in a list of values

    【讨论】:

    • ToStringElements 是什么?
    • 查看我的帖子底部(不知道为什么它保留在上一行 - 我将对其进行编辑以使其更明显)
    • 为什么不使用String.JoinToStringElements 哪个更好?
    • 我猜只是习惯使用它:) 但是,你的建议更好,所以我会更新答案。
    【解决方案3】:

    这样的事情会起作用

    using System;
    using System.Linq;
    using System.Xml.Linq;
    using System.Xml.XPath;
    
    class Program
    {
        static void Main()
        {
            var notNeededBarNames = new[] {1, 3};
            var elems = new[] {"Bars1", "Bars2", "Gubbins3"};
            var newXDoc = new XElement("root");
            var xDoc = XDocument.Load("PathToYourXmlFile");
            foreach (var elem in elems)
            {
                newXDoc.Add(new XElement(elem));
                var curElem = newXDoc.Elements(elem).Single();
                string xpath = String.Format("root/{0}/Bar", elem);
                var childElems = xDoc.XPathSelectElements(xpath);
                foreach (var childElem in childElems)
                {
                    bool add = true;
                    var nameAtt = childElem.Attribute("name");
                    if (nameAtt != null)
                    {
                        int val = Convert.ToInt32(nameAtt.Value);
                        if (notNeededBarNames.Any(x => x == val))
                        {
                            add = false;
                        }
                    }
                    if (add)
                    {
                        curElem.Add(childElem);   
                    }
                }
            }
            var newXml = newXDoc.ToString();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-12
      • 2017-07-30
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多