Reputation: 19707
I'm doing some transforms using xlinq and some of those transforms can result in leaving empty elements in the document.
Once I am done all of those transforms, how can I query an xdocument for all empty elements?
In other words; if I remove all <a>
tags which happen to be the only element inside an <li>
tag, how do I remove the empty <li>
?
Before:
XDocument.Parse(@"<body>
<ul><li><a href="#">Joy</a></li></ul>
<p>Hi.</p>
</body>").Descendants("a").Remove();
After:
<body>
<ul><li/></ul>
<p>Hi.</p>
</body>
I would prefer:
<body>
<p>Hi.</p>
</body>
Upvotes: 1
Views: 4101
Reputation: 2367
Checking for both IsEmpty and HasAttributes is more helpful.
var emptyElements = document.Descendants()
.Where(element => element.IsEmpty
&& !element.HasAttributes);
while (emptyElements.Any())
{
emptyElements.Remove();
}
IsEmpty will return true for elements with just attributes. Eg:
<Participant xsi:nil="true"/>
Upvotes: 0
Reputation: 49564
The accepted answer here is not quite right. Specifically, it will only remove elements that are in the form <foo />
and will leave elements like <foo></foo>
.
As such, here is a complete solution:
public static void RemoveEmptyDescendants(this XNode node)
{
var empty = from e in node.Descendants()
where !e.Nodes().Any() && !e.Attributes().Any()
select e;
while (empty.Any())
{
empty.Remove();
}
}
Upvotes: 0
Reputation: 21
Give XmlNodeList to this function an try this code Hope this will work to remove all empty element and attribute from XMl file
public static XmlNode RemoveNullElement(XmlNodeList xmlNodeList)
{
if (xmlNodeList.Count > 0)
{
foreach (XmlNode xmlnode in xmlNodeList)
{
RemoveNullChildAndAttibute(xmlnode);
return xmlnode;
}
}
return null;
}
public static void RemoveNullChildAndAttibute(XmlNode xmlNode)
{
if (xmlNode.HasChildNodes)
{
for (int xmlNodeCount = xmlNode.ChildNodes.Count - 1; xmlNodeCount >= 0; xmlNodeCount--)
{
RemoveNullChildAndAttibute(xmlNode.ChildNodes[xmlNodeCount]);
}
}
else if (xmlNode.Attributes.Count == 0)
{
if (xmlNode.ParentNode != null)
{
xmlNode.ParentNode.RemoveChild(xmlNode);
}
}
}
Upvotes: 1
Reputation: 1461
Checking if element doesn't have attributes and doesn't have elements is not enough. You need to check if an element is truly empty (absolutely no content). XElement has a property, that actually helps you do that - XElement.IsEmpty.
var document = XDocument.Parse(@"<body><ul><li><a href='#'>Joy</a></li></ul><p>Hi.</p></body>");
document.Descendants("a").Remove();
var emptyElements = from element in document.Descendants()
where element.IsEmpty
select element;
while (emptyElements.Any())
emptyElements.Remove();
Upvotes: 10
Reputation: 19707
The best I could come up with was...
var emptyElements =
from element in document.Descendants()
where !element.Attributes().Any() && !element.Elements().Any()
select element;
while(emptyElements.Any())
emptyElements.Remove();
Then I realized that was a bad idea, it was removing too much but I didn't take the time to figure out why.
Upvotes: 0