Это означает улучшение принятого ответа для обработки атрибутов:
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();
Идея состоит в том, чтобы проверить, что все атрибуты элемента также пусты перед его удалением. Существует также случай, когда пустые потомки могут иметь непустые атрибуты.Я вставил третье условие, чтобы проверить, что у элемента есть все пустые атрибуты среди его потомков. Учитывая следующий документ с добавленным 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>
Это станет:
<root>
<node2 blah="" adf="2"></node2>
<node5><![CDATA[asdfasdf]]></node5>
<node6 xmlns="urn://blah" d="a" />
<node8>
<child2 d='a' />
</node8>
</root>
Исходный и улучшенный ответ на этот вопрос потеряли бы узлы node2
и node6
и node8
.Проверка на e.IsEmpty
будет работать, если вы хотите удалить только узлы, такие как <node />
, но это избыточно, если вы собираетесь использовать и <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();
, что даст вам:
<root>
<node2 adf="2"></node2>
<node5><![CDATA[asdfasdf]]></node5>
<node6 xmlns="urn://blah" d="a" />
</root>