将XML名称空间浮动到根

本文关键字:空间 XML | 更新日期: 2023-09-27 18:02:47

我在c#程序中有一个XML,看起来像这样:

<el1 xmlns="http://URI1">
    <el2 xmlns:namespace2="http://URI2"></el2>
    <el3>
        <el4 xmlns:namespace3="http://URI3"></el4>
    </el3>
</el1>

为了整洁,我想把所有的命名空间声明移到根元素中。我无法更改生成此XML的导出,因此需要一个解决方案来处理上面所示的示例。实现这一目标的好方法是什么?

为简洁起见,本例被简化了,但假设有更多的子元素实际使用这些前缀。这些与这个问题无关,因为所有命名空间前缀声明都是唯一的,我的目标只是将它们移动到树的更高位置。

我已经查看了XML的MSDN文档,但是似乎没有像这样操作名称空间的简单方法。我尝试过的解决方案之一是作为XElement与XML交互,并基于XAttribute收集名称空间。IsNamespaceDeclaration,用其本地名称替换每个元素,最后用收集到的名称空间XAttributes列表创建一个新的根元素。然而,这一系列的实验导致了一堆关于重新定义前缀的错误,我不确定我是否在正确的方向上移动。

将XML名称空间浮动到根

你需要添加一个前缀

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication2
{
    class Program
    {
        const string FILENAME = @"c:'temp'test.xml";
        static void Main(string[] args)
        {
            El1 el1 = new El1()
            {
                el2 = new El2()
                {
                    el3 = new El3() {
                        el4 = new El4() {
                        }
                    }
                }
            };
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("u4", "http://URI4");
            ns.Add("u3", "http://URI3");
            ns.Add("u2", "http://URI2");
            ns.Add("", "http://URI1");
            XmlSerializer serializer = new XmlSerializer(typeof(El1));
            StreamWriter writer = new StreamWriter(FILENAME);
            serializer.Serialize(writer, el1, ns);
            writer.Flush();
            writer.Close();
            writer.Dispose();
        }
    }
    [XmlRoot("el1", Namespace = "http://URI1")]
    public class El1
    {
        [XmlElement("el2", Namespace = "http://URI2")]
        public El2 el2 { get; set; }
    }
    [XmlRoot("el2")]
    public class El2
    {
        [XmlElement("el3", Namespace = "http://URI3")]
        public El3 el3 { get; set; }
    }
    [XmlRoot("el3", Namespace = "http://URI3")]
    public class El3
    {
        [XmlElement("el4", Namespace = "http://URI4")]
        public El4 el4 { get; set; }
    }
    [XmlRoot("el4", Namespace = "http://URI1")]
    public class El4
    {
    }
}
​

您可以使用namespace xpath轴定位所有xml属性。将这些属性添加到根元素。最后,使用NamespaceHandling.OmitDuplicates写出xml,这将把名称空间声明留在根目录中,并从所有其他元素中删除它们。

var xml = new XmlDocument();
xml.Load("XMLFile1.xml");
// Find all xmlns: attributes
var attributes = xml.DocumentElement.SelectNodes("//namespace::*");
// Add xmlns: attributes to the root
foreach (XmlAttribute attribute in attributes)
    xml.DocumentElement.SetAttribute(attribute.Name, attribute.Value);
// Write out results, ignoring duplicate xmlns: attributes
var settings = new XmlWriterSettings();
settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
settings.Indent = true;
using (var writer = XmlWriter.Create("XMLFile2.xml", settings))
{
    xml.Save(writer);
}