XML序列化注释

时间:2009-04-06 06:44:29

标签: c# xml serialization xml-serialization xelement

我的情况是我有一个我不想修改的xml文件。 XElement类中的AddAnnotation函数提供了一个选项,用于添加未编译的内存数据,而不是XML的一部分。

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

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

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

你有什么建议我怎么做这样的事情?

编辑:我应该使用xml处理说明吗?处理说明是否适用于此类用途?

2 个答案:

答案 0 :(得分:2)

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

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

(其中myData是namespace-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();
        }
    }

答案 1 :(得分:1)

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

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

在您的类型中,您可以拥有一个用于保存注释/文档的字段/属性。用XmlIgnore装饰它。然后,创建一个不接受覆盖的XmlSerializer实例。注释不会被序列化或反序列化。使用XmlAttributeOverrides对象为该类型创建另一个XmlSerializer实例。指定XmlIgnore'd属性的覆盖(使用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>