如何将 XML 命名空间提升到根元素

How to hoist XML namespaces to root element

如果我有一个 XML 文件,其命名空间如下:

<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>

我想将所有命名空间提升到根元素,如下所示:

<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>

有办法吗?理想情况下自动解决冲突的名称空间前缀,如上例所示。我还没有承诺将 Linq 用于 XMLSystem.Xml,所以两者都有可能。

有一个主要的限制:因为我工作的环境,我不能写classes。我可以编写函数,但没有新的 class 定义。

原来这很简单:

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++;
}

我们遍历所有名称空间声明 (xmlns:foo="foo")。对于我们找到的每一个,我们在根元素上放置一个具有相同 URL 的名称空间属性,然后删除那个。

Demo.

请注意,如果您有多个具有相同 URL 的命名空间(例如,如果您在不同的 children 上有两批 xmlns:h="https://www.namespaces.com/namespaceOne"),这会有些奇怪:它会放置多个xmlns 根元素上的声明与 URL 相同,但所有元素都使用最后一个这样的命名空间。如果您想避免这种情况,只需保留您已添加到根元素的名称空间列表。