Как поднять XML пространства имен к элементу root - PullRequest
1 голос
/ 11 февраля 2020

Если у меня есть файл 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, например:

<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 для XML или System. Xml, поэтому любой из них был бы возможен.

Существует одно основное ограничение: из-за среды, в которой я работаю, я не могу писать классы. Я могу писать функции, но нет новых определений классов.

1 Ответ

2 голосов
/ 11 февраля 2020

Оказывается, это довольно просто:

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

Мы выполняем oop через все объявления пространства имен (xmlns:foo="foo"). Для каждого найденного нами мы помещаем атрибут пространства имен с тем же URL-адресом в элемент root и удаляем его.

Demo .

Обратите внимание, что это делает несколько странные вещи, если у вас есть несколько пространств имен с одним и тем же URL (например, если у вас есть два лота xmlns:h="https://www.namespaces.com/namespaceOne" на разных дочерних элементах): он помещает несколько объявлений xmlns в элемент root с одним и тем же URL, но все элементы используйте последнее такое пространство имен. Если вы хотите избежать этого, просто сохраните список пространств имен, которые вы добавили к элементу root.

...