如何删除所有空的XElements

7
这个有点棘手。假设我有这个XmlDocument。
<Object>
    <Property1>1</Property1>
    <Property2>2</Property2>
    <SubObject>
         <DeeplyNestedObject />
    </SubObject>
</Object>

我希望恢复这个

<Object>
    <Property1>1</Property1>
    <Property2>2</Property2>
</Object>

由于每个<SubObject>的子元素都是空元素,我想把它们去掉。使情况更具挑战性的是,在迭代节点时无法删除节点。非常感谢任何帮助。

更新 这是我最终得到的结果。

public XDocument Process()
{
    //Load my XDocument
    var xmlDoc = GetObjectXml(_source);

    //Keep track of empty elements
    var childrenToDelete = new List<XElement>();

    //Recursively iterate through each child node
    foreach (var node in xmlDoc.Root.Elements())
        Process(node, childrenToDelete);

    //An items marked for deletion can safely be removed here
    //Since we're not iterating over the source elements collection
    foreach (var deletion in childrenToDelete)
        deletion.Remove();

    return xmlDoc;
}

private void Process(XElement node, List<XElement> elementsToDelete)
{
    //Walk the child elements
    if (node.HasElements)
    {
        //This is the collection of child elements to be deleted 
        //for this particular node
        var childrenToDelete = new List<XElement>();

        //Recursively iterate each child
        foreach (var child in node.Elements())
            Process(child, childrenToDelete);

        //Delete all children that were marked as empty
        foreach (var deletion in childrenToDelete)
            deletion.Remove();

        //Since we just removed all this nodes empty children
        //delete it if there's nothing left
        if (node.IsEmpty)
            elementsToDelete.Add(node);
    }

    //The current leaf node is empty so mark it for deletion
    else if (node.IsEmpty)
        elementsToDelete.Add(node);
}

如果有人对此感兴趣,它的用途是为我整理的一个ObjectFilter项目。 ObjectFilter

使用 System.Xml 读取配置文件。 - Saroop Trivedi
4
请阅读问题。 - SLaks
@SLaks:我在项目中执行相同的操作。你可以阅读XML文档,然后更新文件并最后保存XML。 - Saroop Trivedi
@sarooptrivedi:是的。他正在问如何做到这一点。 - SLaks
@SLaks:给我20分钟,完成我的工作后,我会提供所有源代码。 - Saroop Trivedi
2个回答

9

虽然速度会比较慢,但你可以这样做:

XElement xml;
while (true) {
    var empties = xml.Descendants().Where(x => x.IsEmpty && !x.HasAttributes).ToList();
    if (empties.Count == 0)
        break;

    empties.ForEach(e => e.Remove());
}

为了提高速度,你可以在第一次迭代后向上遍历父节点并查看它们是否为空。
XElement xml;
var empties = xml.Descendants().Where(x => x.IsEmpty && !x.HasAttributes).ToList();
while (empties.Count > 0) {
    var parents = empties.Select(e => e.Parent)
                         .Where(e => e != null)
                         .Distinct()    //In case we have two empty siblings, don't try to remove the parent twice
                         .ToList();

    empties.ForEach(e => e.Remove());

    //Filter the parent nodes to the ones that just became empty.
    parents.RemoveAll(e => e.IsEmpty && !e.HasAttributes);
    empties = parents;
}

我曾经遇到过同样的问题,而这个解决方案只删除了一些元素,留下了空字符串值。这个修改有所帮助:var empties = xml.Descendants().Where(x => (x.IsEmpty || string.IsNullOrEmpty(x.Value)) && !x.HasAttributes).ToList(); - user5226582

-1

在这里,我创建了一个XML文件,在其中放置了所有的XML代码。您也可以使用XmlLoad("")来加载XML。这将是一个带有文件加载的工作代码。您也可以尝试使用XmlLoad。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load("Test.xml");
            XmlElement root = doc.DocumentElement;
            foreach (var item in root)
            {
                XmlElement elem = (XmlElement)item;
                if (elem.InnerText.Equals(""))
                {
                    foreach (var child in elem.ChildNodes)
                    {
                        XmlElement childelem = (XmlElement)child;
                        childelem.RemoveAll();
                    }

                    elem.ParentNode.RemoveChild(elem);
                }
            }
            doc.Save("Test.xml");
            Console.ReadLine();
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接