使用C#使用命名空间反序列化XML片段

时间:2015-04-21 14:40:25

标签: c# xml deserialization xml-deserialization

我遇到了反序列化以下XML片段(来自OneNote)的问题:

<one:OE creationTime="2015-03-21T18:32:38.000Z" lastModifiedTime="2015-03-21T18:32:38.000Z" objectID="{649CA68C-C596-4F89-9885-1553A953529E}{30}{B0}" alignment="left" quickStyleIndex="1" selected="partial">
    <one:List>
        <one:Bullet bullet="2" fontSize="11.0" />
    </one:List>
    <one:T><![CDATA[Bullet point one]]></one:T>
</one:OE>

以下代码用于反序列化上述片段。 OE类具有以下属性:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34230")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://schemas.microsoft.com/office/onenote/2013/onenote")]
[System.Xml.Serialization.XmlRootAttribute("OE", Namespace = "http://schemas.microsoft.com/office/onenote/2013/onenote", IsNullable = true)]
public partial class OE : EntityBase<OE>
{
    ...
}

反序列化片段的实际方法是在基类EntityBase:

public static T Deserialize(string xml)
{
    System.IO.StringReader stringReader = null;
    try
    {
        stringReader = new System.IO.StringReader(xml);
        return ((T)(Serializer.Deserialize(System.Xml.XmlReader.Create(stringReader))));
    }
    finally
    {
        if ((stringReader != null))
        {
            stringReader.Dispose();
        }
    }
}

deserialize方法调用如下:

var element = OE.Deserialize(xmlString);

变量xmlString是上面给出的XML片段。在调用Deserialize方法时,我收到以下错误:

There is an error in XML document (1,2). ---> System.Xml.XmlException: 'one' is an undeclared prefix. Line 1, position 2.

我花了一些时间查看声明OE类中名称空间的属性,但一切看起来都是正确的。谁能指出我正在犯的错误?

2 个答案:

答案 0 :(得分:2)

answer给出的matrixanomaly是正确的,但不幸的是,给出的O​​neNote命名空间不正确。我正在使用OneNote 2013而不是2010.我用来反序列化我在问题中给出的相同XML片段的实际代码如下:

public static OE DeserializeFragment(string xmlFragment)
{
    var serializer = new System.Xml.Serialization.XmlSerializer(typeof(OE));
    System.IO.StringReader stringReader = null;
    try
    {
        stringReader = new System.IO.StringReader(xmlFragment);

        NameTable nt = new NameTable();
        XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
        nsManager.AddNamespace("one", "http://schemas.microsoft.com/office/onenote/2013/onenote");
        XmlParserContext context = new XmlParserContext(null, nsManager, null, XmlSpace.None);
        XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
        xmlReaderSettings.ConformanceLevel = ConformanceLevel.Fragment;

        return ((OE)(serializer.Deserialize(System.Xml.XmlReader.Create(stringReader, xmlReaderSettings, context))));
    }
    finally
    {
        if ((stringReader != null))
        {
            stringReader.Dispose();
        }
    }
}

答案 1 :(得分:1)

我认为您需要one的原始名称空间声明。这是因为one是一个命名空间,OEList之类的项是前缀,它们存在于oneNote创建的命名空间中,声明不会出现在片段中发布。存在前缀以避免在不同XML文档混合在一起时命名中的冲突。 see a w3schools link for further explanation

因此,解决方法是将<xmlns:one="http://schemas.microsoft.com/office/onenote/2010/onenote">这样的命名空间附加到每个片段(似乎不是最优的,但是它可以工作),然后按照你的方式对其进行反序列化。已完成。

我没有方便的OneNote,因此名称空间声明为from this forum post

反序列化XML片段的另一种方法是通过 XMLReader 和XMLReaderSettings,您可以将coformance级别设置为 Fragment 。并添加一个预定义的命名空间。

改编自this MSDN blog

的示例
 XmlDocument doc = new XmlDocument();

        NameTable nt = new NameTable();
        XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
        nsmgr.AddNamespace("one", "http://schemas.microsoft.com/office/onenote/2010/onenote");
        XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);
        XmlReaderSettings xset = new XmlReaderSettings();
        xset.ConformanceLevel = ConformanceLevel.Fragment;
        XmlReader rd = XmlReader.Create(new  StringReader(XMLSource), xset, context); 

        doc.Load(rd);

我个人更喜欢使用XMLReader和XMLReader设置,虽然它们似乎需要更多工作CreateReader()并进行设置,但它看起来更加强大。

,如果您不想处理自定义命名空间而不想处理碰撞问题,请以编程方式删除{的前端声明{1}},继续反序列化。不过,这更像是字符串操作。