如何在没有每个组件名称空间的情况下将多个对象序列化到现有XmlDocument中? [英] How to serialize multiple objects into an existing XmlDocument, without having the namespaces on each component?

查看:75
本文介绍了如何在没有每个组件名称空间的情况下将多个对象序列化到现有XmlDocument中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将多个对象序列化为.Net / C#中的现有XmlDocument?

How to serialize multiple objects into a existing XmlDocument in .Net/C#?

我有一个XmlDocument,其中已经包含数据。我有多个对象。现在,我要一个接一个地序列化它们,并将它们添加到XmlDocument(AppendChild)中。

I have a XmlDocument, which already contains data. I have multiple objects. Now I want to serialize them one by one and add them to the XmlDocument (AppendChild).

应该是这样的:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<project>
    <mySettings>...</mySettings>
    <component_1> anydata </component_1>
    ...
    <component_x> anydata </component_x>
</project>

当我使用XmlSerializer时,每个组件的定义如下:

When I use the XmlSerializer I get this definition for each component:

<component_1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    anydata
</component_1>

这就是我得到的,当我序列化为字符串然后从字符串创建XmlNode时,我将其附加到我的文档中:

So this is what I get, when I serialize into a string and then create a XmlNode from string, which i append to my document:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<project>
    <mySettings>...</mySettings>
    <component_1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> anydata </component_1>
    ...
    <component_x xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> anydata </component_x>
</project>

我可以通过执行以下操作删除命名空间:

I can remove the namespace by doing this:

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
StringWriter xout = new StringWriter();
x.Serialize(xout, data, ns);

但是随后我得到对象数组内任何对象的名称空间。此对象:

But then I get the namespaces on any object inside an object array. This object:

public class component_1
{
    object[] arr;
}

将序列化为:

<component_1>
  <objectArray>
    <anyType xmlns:q1="http://www.w3.org/2001/XMLSchema" d3p1:type="q1:string" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">one</anyType>
    <anyType xmlns:q2="http://www.w3.org/2001/XMLSchema" d3p1:type="q2:string" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">two</anyType>
  </objectArray>
</component_1>

是否可以将所有需要的名称空间等添加到我的文档中,然后将对象序列化为XmlNodes和将它们添加到我的文档中,而没有每个组件上的命名空间吗?

Is it possible to add all needed namespaces, etc. to my document and then serialize objects into XmlNodes and add them to my document, without having the namespaces on each component?

更新:
函数test()将序列化两个对象并将它们附加到文档中。
最后一行将反序列化第一个对象。

UPDATE: The function test() will serialize two objects and append them to a document. Last line will deserialize the first object.

using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
...

public class Component_1
{
    public string Value = "Component_1.Value";
    public object[] objectArray = new object[] { "one", "two" };
}
void test()
{
    object[] components = new object[] { new Component_1(), new Component_1() };

    XmlDocument doc = new XmlDocument();
    XmlNode rootNode = doc.AppendChild(doc.CreateElement("project"));

    foreach (var component in components)
        rootNode.AppendChild(doc.ReadNode(XmlTextReader.Create(new StringReader(serialize(component, true)))));

    Console.WriteLine(doc.OuterXml);
    Console.WriteLine(deserialize<Component_1>(rootNode.ChildNodes[0].OuterXml).Value);
}
string serialize(object obj, bool namespaces)
{
    StringBuilder sb = new StringBuilder();
    XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { OmitXmlDeclaration = true });
    (new XmlSerializer(obj.GetType())).Serialize(writer, obj, namespaces ? null : new XmlSerializerNamespaces(new XmlQualifiedName[] { new XmlQualifiedName("", "") }));
    return sb.ToString();
}
T deserialize<T>(string xmlString)
{
    return (T)(new XmlSerializer(typeof(T))).Deserialize(new StringReader(xmlString));
}

也许可以在文档(rootNode)中以及创建时添加名称空间带有功能XmlDocument.ReadNode的字符串中的新XmlNode,以通过XmlDocument中的名称空间解析字符串中的名称空间。但是我不知道如何。

Maybe it is possible to add namespaces to the document (rootNode) and when creating a new XmlNode from string with the function XmlDocument.ReadNode to resolve the namespaces in string by the namespaces from XmlDocument. But I don´t know how.

更新2:

感谢Alex Filipovici,序列化输出正是我想要的。

UPDATE 2:
Thanks Alex Filipovici, the serialization output is exact what I wanted.

void test2()
{
    object[] components = new object[] { new Component_1(), new Component_1() };

    var doc = new XmlDocument();

    var project = doc.AppendChild(doc.CreateElement("project"));

    doc.DocumentElement.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    doc.DocumentElement.SetAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");

    var nav = project.CreateNavigator();

    var emptyNamepsaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });

    foreach (var component in components)
    {
        using (var writer = nav.AppendChild())
        {
            var serializer = new XmlSerializer(component.GetType());
            writer.WriteWhitespace("");
            serializer.Serialize(writer, component
                , emptyNamepsaces
                );
            writer.Close();
        }
    }

    foreach (XmlNode node in doc.GetElementsByTagName("anyType"))
    {
        string attributeType = "";
        foreach (XmlAttribute xmlAttribute in node.Attributes)
        {
            if (xmlAttribute.LocalName == "type")
            {
                attributeType = xmlAttribute.Value.Split(':')[1];
            }
        }
        node.Attributes.RemoveAll();
        node.CreateNavigator().CreateAttribute("", "type", "", attributeType);
    }
    doc.Save("output.xml");

    Component_1 c = deserialize<Component_1>(project.ChildNodes[0].OuterXml);

    Console.WriteLine(c.objectArray[0].GetType()); // -> System.Xml.XmlNode[] !
}

输出:

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Component_1>
    <Value>Component_1.Value</Value>
    <objectArray>
      <anyType type="string">one</anyType>
      <anyType type="string">two</anyType>
    </objectArray>
  </Component_1>
  <Component_1>
    <Value>Component_1.Value</Value>
    <objectArray>
      <anyType type="string">one</anyType>
      <anyType type="string">two</anyType>
    </objectArray>
  </Component_1>
</project>

但是现在从上面使用 T desirialize(string xmlString)函数进行反序列化失败。对象数组包含XmlNodes。

But now the deserialization with the "T desirialize(string xmlString)" function from above fails. The object array contains XmlNodes.

是否可以告诉XmlSerializer使用项目节点中的名称空间,还是必须再次插入它们?

Is it possible to tell XmlSerializer to use the namespaces from the project node, or do I have to insert them again?

推荐答案

这将序列化对象并将其附加到XmlDocument。
反序列化时,代码将解析名称空间。
@Alex:感谢使用XPathNavigator的示例。

This will serialize objects and append them to a XmlDocument. While de-/serializing the code will resolve the namespaces. @Alex: Thanks for the example with XPathNavigator.

void test2()
{
    XmlDocument doc = new XmlDocument();
    XmlNode root = doc.AppendChild(doc.CreateElement("root"));

    doc.DocumentElement.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    doc.DocumentElement.SetAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");

    serializeAppend(root, new object[] { 1, "two", 3.0 });  // serialize object and append it to XmlNode
    var obj = deserialize<object[]>(root.ChildNodes[0]);    // deserialize XmlNode to object
}
T deserialize<T>(XmlNode node)
{
    XPathNavigator nav = node.CreateNavigator();
    using (var reader = nav.ReadSubtree())
    {
        var serializer = new XmlSerializer(typeof(T));
        return (T)serializer.Deserialize(reader);
    }
}
void serializeAppend(XmlNode parentNode, object obj)
{
    XPathNavigator nav = parentNode.CreateNavigator();
    using (var writer = nav.AppendChild())
    {
        var serializer = new XmlSerializer(obj.GetType());
        writer.WriteWhitespace("");
        serializer.Serialize(writer, obj);
        writer.Close();
    }
}

这篇关于如何在没有每个组件名称空间的情况下将多个对象序列化到现有XmlDocument中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆