Reputation: 535
(Note: This is NOT a semantic question. This isn't asking about what self closing tags mean. This is about doing the opposite with XDocument than what is mentioned in this example post with C#: Remove self-closing tags (e.g. />) in an XmlDocument).
I'm writing this because I've found so many posts on here and elsewhere that ask about a good way to change self-closing tags in a C# XDocument object to an open and close tag with an empty value.
I want to do the opposite. I want to change this:
<GovtID id="1"></GovtID>
to this:
<GovtID id="1"/>
I want to preserve all attributes and their values that were in the element from before, EXCEPT empty values.
Here's the latest thing I've tried:
private static void CleanUpXElements(XDocument doc)
{
foreach (XElement childElement in
from x in doc.DescendantNodes().OfType<XElement>()
where x.Value == string.Empty
select x)
{
childElement.ReplaceWith(new XElement(childElement.Name.LocalName, childElement.Attributes()));
};
}
However, when I use this approach, I get a Null Exception when the child element in question gets replaced this way.
Is there a way I can do this without throwing a Null Reference Exception? I see the element change to a self closing tag, but then the Null Exception happens.
Upvotes: 1
Views: 82
Reputation: 116516
I think your problem may be that you are modifying the document's element tree while iterating through it, causing the iterator to throw an exception when it tries to proceed past the modification.
As an alternative, you could iterate through the elements and, for every element that has no child elements and an empty value, completely remove all child nodes:
public static void CleanUpXElements(this XDocument doc)
{
foreach (XElement childElement in
from x in doc.Descendants()
where !x.IsEmpty && !x.Elements().Any() && string.IsNullOrEmpty(x.Value)
select x)
{
childElement.RemoveNodes();
};
}
This avoids modifying the element tree while iterating through it and results in <GovtID id="1" />
Demo fiddle here.
Be aware that, as noted by kjhughes, the two empty element forms <GovtID id="1"></GovtID>
and <GovtID id="1" />
are semantically identical. As such it should not be necessary to convert one form to the other, and any code that depends on the difference between them is likely broken.
Finally, if your underlying problem is that
XmlSerializer
.<GovtID>
is defined to be an int
or int?
or Guid?
or other primitive (non-string) value type in your data model.<GovtID></GovtID>
.Then see Deserializing empty xml attribute value into nullable int property using XmlSerializer. This answer by bvdb to Self-closing tags in XML files would also apply.
Upvotes: 1