【问题标题】:XML Deserialization C# gives error for valid documentXML 反序列化 C# 为有效文档提供错误
【发布时间】:2017-01-27 04:24:18
【问题描述】:

我有很多结构相同的 XML 文件。他们中的许多人工作正常,但是对于某些 XmlSerializer 给了我一个错误,但是当我将文档放入 xml 验证器时 - 它说文档是正确的。

反序列化代码:

var document = serializer.Deserialize(File.OpenRead(file));

错误:

System.InvalidOperationException: There is an error in XML document (504, 8). ---> System.Xml.XmlException: Unexpected node type Element. ReadElementString method can only be called on elements with simple or empty content. Line 504, position 8.
  at System.Xml.XmlReader.ReadElementString()
  at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderPatentdocument.Read33_Claimtext(Boolean isNullable, Boolean checkType)
  at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderPatentdocument.Read34_Claim(Boolean isNullable, Boolean checkType)
  at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderPatentdocument.Read35_Claims(Boolean isNullable, Boolean checkType)
  at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderPatentdocument.Read43_Patentdocument(Boolean isNullable, Boolean checkType)
  at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderPatentdocument.Read44_patentdocument()
  --- End of inner exception stack trace ---
  at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
  at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)

给出错误的文档部分:

<text>12. Führungsschiene nach einem der Ansprüche 2 bis 11, dadurch gekennzeichnet, daß in den beiden Nutwänden (<b>11<i>a</i>, 11</b><i>a′)</i> einander gegenüberliegende Bohrungen (<b>14</b><i>a</i>, <b>14</b><i>a</i>′) vorgesehen sind, von denen die eine Bohrung (<b>14</b><i>a</i>′) durch das Einsatzteil (<b>15</b><i>a)</i> ver­schlossen ist.</text>

我想这是因为里面的内联html标签,因为它在i标签的位置抱怨这条线

<b>11<i>a</i>, 11</b>

但是例如根据 XmlSerializer 这个 xml 是正确的,并且可以反序列化它:

<text>9. Führungsschiene nach Anspruch 8, dadurch gekennzeichnet, daß der Ansatz (<b>20</b>) die Zuführfläche (<b>25</b>) aufweist.</text>

所以我的问题是为什么 xml 验证器说文档是有效的,而 XmlSerializer 不能反序列化它?是否可以在不更改文档的情况下找到解决方法?

【问题讨论】:

  • 您的应用程序中需要一组与 xml 文件匹配的类。序列化/反序列化不是自动的。
  • 文档不是有效的 XML。它包含名为bi未知XML 标记。如果要将 HTML 字符串包含在 XML 文档中,则必须对其进行 编码
  • @CharlesMager 检查错误消息 - 反序列化器抱怨一个简单的元素。调用堆栈显示反序列化程序是从 XSD 生成的,该 XSD 需要 &lt;text&gt; 元素中的文本。 XSD 错误,或者序列化程序中存在错误。如果数据来自第三方,则 OP 可能必须找到处理无效数据的方法
  • @syned 验证器没有提到 XSD,只有旧的 DTD。您只是复制了文件还是包含了指向有效 DTD 的链接?如果你只是复制文件,结果是没有意义的。问题是您用来生成反序列化器的 XSD 需要 简单文本内容 用于 &lt;text&gt;。您是否根据一些示例生成了 XSD?
  • 不要混淆 validwell-formed xml!您的 xml 格式正确,因此 XmlSerializer 通常可以反序列化。但是根据类的定义,您的 XML 无效。显然,您应该将bi 添加到您的类属性中。

标签: c# .net xml xml-deserialization


【解决方案1】:

假设我们有以下类:

public class Foo
{
    //[XmlIgnore]
    public string Text { get; set; }
}

还有如下形式的xml:

<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <text>12. Führungsschiene nach einem der Ansprüche 2 bis 11, dadurch gekennzeichnet, daß in den beiden Nutwänden (<b>11<i>a</i>, 11</b><i>a′)</i> einander gegenüberliegende Bohrungen (<b>14</b><i>a</i>, <b>14</b><i>a</i>′) vorgesehen sind, von denen die eine Bohrung (<b>14</b><i>a</i>′) durch das Einsatzteil (<b>15</b><i>a)</i> ver­schlossen ist.</text>
</Foo>

那么我们可以对数据进行如下反序列化。

var xs = new XmlSerializer(typeof(Foo));
xs.UnknownElement += Xs_UnknownElement;

Foo foo;
using (var fs = new FileStream("test.txt", FileMode.Open))
{
    foo = (Foo)xs.Deserialize(fs);
}

订阅XmlSerializerUnknownElement 活动。

在事件处理程序中手动将我们的属性设置为数据。

private static void Xs_UnknownElement(object sender, XmlElementEventArgs e)
{
    var foo = (Foo)e.ObjectBeingDeserialized;
    foo.Text = e.Element.InnerXml;
}

请注意,属性名称不应与 xml 节点名称匹配(区分大小写)。只有在这种情况下才会触发事件。如果名称匹配,请使用XmlIgnore 属性。

【讨论】:

    【解决方案2】:

    尝试序列化导致您出现问题的实例。然后,您可以将序列化的输出与您尝试反序列化的文件的内容进行比较。两个 XML 字符串之间的差异会告诉您问题出在哪里。

    这是一个将类的实例序列化为 XML 的快速函数:

        public static string Serialize<T>(T entity)
        {
            if (entity == null)
                return String.Empty;
    
            try
            {
                XmlSerializer XS = new XmlSerializer(typeof(T));
                System.IO.StringWriter SW = new System.IO.StringWriter();
                XS.Serialize(SW, entity);
                return SW.ToString();
            }
            catch (Exception e)
            {
                Logging.Log(Severity.Error, "Unable to serialize entity", e);
                return String.Empty;
            }
        }
    

    如果您还没有尝试过,我建议您使用软件BeyondCompare 轻松查看两个文件之间的区别。

    【讨论】:

    • 我没有序列化这些文档,我将它们作为输入
    • 我明白了。我不确定这是否可能,但您可以使用输入中的数据手动编写一个实例吗?
    【解决方案3】:

    当您指向内部 HTML 标记时,您是对的。 您的 XML 无效,因为您在简单(文本)元素中有标签。 XmlSerializer 看不懂,抛出错误。

    如果您已生成 XML 文件,您必须事先对简单元素中的数据进行转义:

    • 使用 HTML 编码
    • 或将其封装在 CDATA 标记中 (&lt;![CDATA[...]]&gt;)

    【讨论】:

    • XML 无效有效。它在&lt;text&gt; 元素内包含XML 标记。当 HTML 标记出现在 XML 元素(尤其是简单元素)中时,它们不会受到任何特殊处理。
    • 我无权访问生成这些文件的过程。这些是我的输入文件。
    • @DarKalimHero 我没有为文件添加 CDATA 的选项。当然,我可以预处理文件以动态添加 CDATA,然后反序列化它。但如果可能的话,我想避免它
    • 可以在没有编码或CDATA的情况下将html包含在XML中
    • 好的。你到底想做什么?你打算用 XML 做什么?你为什么要反序列化它?也许我们可以找到一些解决方法。
    猜你喜欢
    • 1970-01-01
    • 2013-02-19
    • 2016-04-28
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-13
    • 2018-06-04
    相关资源
    最近更新 更多