【问题标题】:XML serialize annotationsXML 序列化注解
【发布时间】:2009-04-06 06:44:28
【问题描述】:

我有一个不想修改的 xml 文件的情况。 XElement 类中的 AddAnnotation 函数提供了一个选项来添加未序列化且不属于 XML 的仅内存数据。

我希望能够保存这些注释(例如:保存到另一个 xml 文件),然后反序列化 xml 和注释,以便获得与我相同的对象。

我不想更改原始 xml,这就是我使用注释的原因。

总而言之,我希望能够将自定义数据添加到 xml 文件中。当我序列化它时,这些数据不会成为 xml 的一部分,否则它将成为 xml 的一部分,但我可以轻松检索原始 xml。

你有什么建议我可以做这样的事情吗?

编辑:我应该使用 xml 处理指令吗?处理指令是否适用于这种用途?

【问题讨论】:

    标签: c# xml serialization xml-serialization xelement


    【解决方案1】:

    在我看来,最简单的方法是使用常规节点,但在不同的 xml 命名空间中 - 即

    <foo standardAttrubute="abc" myData:customAttribute="def">
        <standardElement>ghi</standardElement >
        <myData:customElement>jkl</myData:customElement>
    </foo>
    

    (其中myData 是命名空间uri 的xmlns 别名)

    在许多情况下,读者只检查 他们的 命名空间(或默认/空白命名空间)中的数据 - 通常会跳过自定义命名空间中的值。

    要打包原始 xml,一种简单的方法是通过仅尊重默认/原始命名空间的 xslt 运行它。


    XNamespace myData = XNamespace.Get("http://mycustomdata/");
    XElement el = new XElement("foo",
        new XAttribute(XNamespace.Xmlns + "myData", myData.NamespaceName),
        new XAttribute("standardAttribute", "abc"),
        new XAttribute(myData + "customAttribute", "def"),
        new XElement("standardElement", "ghi"),
        new XElement(myData + "customAttribute", "jkl"));
    string s = el.ToString();
    

    要从XElement 中删除此类数据,也许:

        static void Strip(XElement el, XNamespace ns) {
            List<XElement> remove = new List<XElement>();
            foreach (XElement child in el.Elements()) {
                if (child.Name.Namespace == ns) {
                    remove.Add(child);
                } else {
                    Strip(child, ns);
                }
            }
            remove.ForEach(child => child.Remove());
    
            foreach (XAttribute child in
                (from a in el.Attributes()
                 where a.Name.Namespace == ns
                 select a).ToList()) {
                child.Remove();
            }
        }
    

    【讨论】:

    • 听起来很有趣...你能提供一个例子(实际上是两个例子)我如何使用 XElement 加载 xml,有和没有自定义属性吗?
    • Creation added - 这就是你的意思吗?还是别的什么?
    • 没有。我知道如何创建 xml。我不知道如何在没有自定义数据的情况下加载它。 tnx!
    • Tnx。可能的小改进 - 也去掉自定义命名空间声明。总的来说,我在想也许使用自定义 XmlReader 会更好。
    • 如果您要降到 XmlReader 级别,我会先查看 xslt... 更容易正确。 XmlReader 不可掉以轻心。
    【解决方案2】:

    最初的问题使用了“序列化”这个词,但后来也提到了 XElement 和注释。对我来说,这是两件不同的事情。

    如果你真的想使用 XmlSerializer:
    我要做的是使用 XmlAttributeOverrides 来区分序列化。 使用 XmlAttributeOverrides,您可以在运行时以编程方式覆盖装饰您的类型的 xml 序列化属性。

    在您的类型中,您可以拥有一个用于保存注释/文档的字段/属性。用 XmlIgnore 装饰它。然后,创建一个不接受任何覆盖的 XmlSerializer 实例。注释不会被序列化或反序列化。使用 XmlAttributeOverrides 对象为该类型创建另一个 XmlSerializer 实例。为 XmlIgnore 的属性指定一个覆盖(使用 XmlElementAttribute),以及对任何其他成员的任何属性的覆盖(使用 XmlIgnore=true)。

    对实例进行两次序列化,每个序列化程序一次。


    编辑:这是代码:

    public class DTO
    {
        [XmlIgnore]
        public string additionalInformation;
    
        [XmlElement(Order=1)]
        public DateTime stamp;
    
        [XmlElement(Order=2)]
        public string name;
    
        [XmlElement(Order=3)]
        public double value;
    
        [XmlElement(Order=4)]
        public int index;
    }
    
    
    
    public class OverridesDemo
    { 
        public void Run()
        {
            DTO dto = new DTO
                {
                    additionalInformation = "This will bbe serialized separately",
                    stamp = DateTime.UtcNow,
                    name = "Marley",
                    value = 72.34,
                    index = 7
                };
    
    
            // ---------------------------------------------------------------
            // 1. serialize normally
            // this will allow us to omit the xmlns:xsi namespace
            var ns = new XmlSerializerNamespaces();
            ns.Add( "", "" );
    
            XmlSerializer s1 = new XmlSerializer(typeof(DTO));
    
            var builder = new System.Text.StringBuilder();
            var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
    
            Console.WriteLine("\nSerialize using the in-line attributes: ");
            using ( XmlWriter writer = XmlWriter.Create(builder, settings))
            {
                s1.Serialize(writer, dto, ns);
            }
            Console.WriteLine("{0}",builder.ToString());
            Console.WriteLine("\n");            
            // ---------------------------------------------------------------
    
            // ---------------------------------------------------------------
            // 2. serialize with attribute overrides
            // use a non-empty default namespace
            ns = new XmlSerializerNamespaces();
            string myns = "urn:www.example.org";
            ns.Add( "", myns);
    
            XmlAttributeOverrides overrides = new XmlAttributeOverrides();
    
            XmlAttributes attrs = new XmlAttributes();
            // override the (implicit) XmlRoot attribute
            XmlRootAttribute attr1 = new XmlRootAttribute
                {
                    Namespace = myns,
                    ElementName = "DTO-Annotations",
                };
            attrs.XmlRoot = attr1;
    
            overrides.Add(typeof(DTO), attrs);
            // "un-ignore" the first property
            // define an XmlElement attribute, for a type of "String", with no namespace
            var a2 = new XmlElementAttribute(typeof(String)) { ElementName="note", Namespace = myns };
    
            // add that XmlElement attribute to the 2nd bunch of attributes
            attrs = new XmlAttributes();
            attrs.XmlElements.Add(a2);
            attrs.XmlIgnore = false; 
    
            // add that bunch of attributes to the container for the type, and
            // specifically apply that bunch to the "additionalInformation" property 
            // on the type.
            overrides.Add(typeof(DTO), "additionalInformation", attrs);
    
            // now, XmlIgnore all the other properties
            attrs = new XmlAttributes();
            attrs.XmlIgnore = true;       
            overrides.Add(typeof(DTO), "stamp", attrs);
            overrides.Add(typeof(DTO), "name",  attrs);
            overrides.Add(typeof(DTO), "value", attrs);
            overrides.Add(typeof(DTO), "index", attrs);
    
            // create a serializer using those xml attribute overrides
            XmlSerializer s2 = new XmlSerializer(typeof(DTO), overrides);
    
            Console.WriteLine("\nSerialize using the override attributes: ");
            builder.Length = 0;
            using ( XmlWriter writer = XmlWriter.Create(builder, settings))
            {
                s2.Serialize(writer, dto, ns);
            }
            Console.WriteLine("{0}",builder.ToString());
            Console.WriteLine("\n");            
            // ---------------------------------------------------------------
        }
    }
    

    输出,使用内联属性:

    <DTO>
      <stamp>2009-06-30T02:17:35.918Z</stamp>
      <name>Marley</name>
      <value>72.34</value>
      <index>7</index>
    </DTO>
    

    输出,使用覆盖属性:

    <DTO-Annotations xmlns="urn:www.example.org">
      <note>This will bbe serialized separately</note>
    </DTO-Annotations>
    

    【讨论】:

      猜你喜欢
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多