If I have an XML file with namespaces like:
<root>
<h:table xmlns:h="http://www.namespaces.com/namespaceOne">
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>
<h:table xmlns:h="https://www.namespaces.com/namespaceTwo">
<h:name>African Coffee Table</h:name>
<h:width>80</h:width>
<h:length>120</h:length>
</h:table>
</root>
I want to hoist all of the namespaces to the root element, like this:
<root xmlns:h="http://www.namespaces.com/namespaceOne" xmlns:h1="https://www.namespaces.com/namespaceTwo">
<h:table>
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>
<h1:table>
<h1:name>African Coffee Table</h1:name>
<h1:width>80</h1:width>
<h1:length>120</h1:length>
</h1:table>
</root>
Is there a way to do this? Ideally automatically resolving conflicting namespace prefixes, as in the example above. I haven't committed to using Linq to XML or System.Xml yet, so either would be a possibility.
There is one major constraint: because of the environment I am working in, I can't write classes. I can write functions, but no new class definitions.
Turns out this is pretty straightforward:
var doc = XDocument.Parse(xml);
var namespaceAttributes = doc.Descendants()
.SelectMany(x => x.Attributes())
.Where(x => x.IsNamespaceDeclaration);
int count = 1;
foreach (var namespaceAttribute in namespaceAttributes)
{
doc.Root.Add(new XAttribute(XNamespace.Xmlns + $"h{count}", namespaceAttribute.Value));
namespaceAttribute.Remove();
count++;
}
We loop through all namespace declarations ( xmlns:foo="foo"
). For each one we find, we put a namespace attribute with the same URL on the root element, and remove that one.
Demo .
Note that this does slightly odd things if you have multiple namespaces with the same URL (eg if you have two lots of xmlns:h="https://www.namespaces.com/namespaceOne"
on different children): it puts multiple xmlns
declarations on the root element with the same URL, but all elements use the last such namespace. If you want to avoid that, just keep a list of namespaces you've added to the root element.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.