删除空XML标记

Min*_*ing 12 .net c# xml linq-to-xml

我正在寻找一种可以有效地从XML中删除空标签的好方法.您有什么推荐的吗?正则表达式?的XDocument?XmlTextReader的?

例如,

const string original = 
    @"<?xml version=""1.0"" encoding=""utf-16""?>
    <pet>
        <cat>Tom</cat>
        <pig />
        <dog>Puppy</dog>
        <snake></snake>
        <elephant>
            <africanElephant></africanElephant>
            <asianElephant>Biggy</asianElephant>
        </elephant>
        <tiger>
            <tigerWoods></tigerWoods>       
            <americanTiger></americanTiger>
        </tiger>
    </pet>";
Run Code Online (Sandbox Code Playgroud)

可能成为:

const string expected = 
    @"<?xml version=""1.0"" encoding=""utf-16""?>
        <pet>
        <cat>Tom</cat>
        <dog>Puppy</dog>        
        <elephant>                                              
            <asianElephant>Biggy</asianElephant>
        </elephant>                                 
    </pet>";
Run Code Online (Sandbox Code Playgroud)

Jam*_*iec 28

将原件加载到XDocument并使用以下代码可以得到所需的输出:

var document = XDocument.Parse(original);
document.Descendants()
        .Where(e => e.IsEmpty || String.IsNullOrWhiteSpace(e.Value))
        .Remove();
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案,但它将删除具有属性但不包含内容的元素,例如`<asdf attr ="val"/>`将被删除,这可能是不可取的.我提供了另一个基于此的答案来补充这一点. (3认同)

Dan*_*eld 16

这是对处理属性的已接受答案的改进:

XDocument xd = XDocument.Parse(original);
xd.Descendants()
    .Where(e => (e.Attributes().All(a => a.IsNamespaceDeclaration || string.IsNullOrWhiteSpace(a.Value))
            && string.IsNullOrWhiteSpace(e.Value)
            && e.Descendants().SelectMany(c => c.Attributes()).All(ca => ca.IsNamespaceDeclaration || string.IsNullOrWhiteSpace(ca.Value))))
    .Remove();
Run Code Online (Sandbox Code Playgroud)

这里的想法是在删除元素之前检查元素上的所有属性是否也为空.还有一种情况是空后代可以具有非空属性.我插入了第三个条件来检查该元素在其后代中是否具有所有空属性. 考虑以下添加了node8的文档:

<root>
  <node />
  <node2 blah='' adf='2'></node2>
  <node3>
    <child />
  </node3>
  <node4></node4>
  <node5><![CDATA[asdfasdf]]></node5>
  <node6 xmlns='urn://blah' d='a'/>
  <node7 xmlns='urn://blah2' />
  <node8>
     <child2 d='a' />
  </node8>
</root>
Run Code Online (Sandbox Code Playgroud)

这会变成:

<root>
  <node2 blah="" adf="2"></node2>
  <node5><![CDATA[asdfasdf]]></node5>
  <node6 xmlns="urn://blah" d="a" />
  <node8>
    <child2 d='a' />
  </node8>
</root>
Run Code Online (Sandbox Code Playgroud)

原来和改进这个问题的答案将失去node2node6node8节点.检查e.IsEmpty将工作,如果你只是想去掉节点等<node />,但如果你要两者是redunant <node /><node></node>.如果您还需要删除空属性,则可以执行以下操作:

xd.Descendants().Attributes().Where(a => string.IsNullOrWhiteSpace(a.Value)).Remove();
xd.Descendants()
  .Where(e => (e.Attributes().All(a => a.IsNamespaceDeclaration))
            && string.IsNullOrWhiteSpace(e.Value))
  .Remove();
Run Code Online (Sandbox Code Playgroud)

这会给你:

<root>
  <node2 adf="2"></node2>
  <node5><![CDATA[asdfasdf]]></node5>
  <node6 xmlns="urn://blah" d="a" />
</root>
Run Code Online (Sandbox Code Playgroud)