Оказывается, это довольно просто:
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.