【问题标题】:XmlSerializer: How to capture file/line/column information for each deserialized element?XmlSerializer:如何捕获每个反序列化元素的文件/行/列信息?
【发布时间】:2015-06-04 20:58:23
【问题描述】:

我正在使用 XML 序列化来读取大型用户输入文件。如果在阅读过程中没有发现输入中的语义错误,我希望能够告诉用户他们可以在哪里(文件、行、列)找到有问题的元素。这可以通过 XML 序列化实现吗?

澄清:有问题的代码是 Compact Framework 的 IoC 容器;许多可能的语义错误与初始化最终对象图时的反射失败等事情有关。这些实际上是运行时错误,而不是读取时或编译时错误。但是,我想告诉他们不仅属性集失败是因为 Blah 类没有属性 Fred,而且有问题的属性集位于 Objects.xml 的第 1337 行。

  • 错误不会导致反序列化异常。输入对反序列化目的有效,并且不包含语法或数据类型错误。
  • 无法通过启用架构验证来检测错误。输入在示意上是有效的。
  • 在读取/反序列化过程中无法检测到错误,因为目标对象的类型可能尚未解析。

【问题讨论】:

  • 你想行号信息放在哪里?我认为没有 IXmlSerializable 就没有办法做到这一点。
  • @John:Martin 自己使用序列化类here

标签: .net xml-serialization


【解决方案1】:

如果您有描述文档的架构,那么您可以在反序列化时使用带有验证功能的 XmlReader。处理验证错误,您就可以为用户提供可能比他们想要的更多的细节。

请注意,XML Schema 验证错误对用户不是很友好。您可能想朝相反的方向工作:让您的用户更难输入无效文档。使用 InfoPath 之类的工具将表单 UI 放置在 XML 实例文档上是一种方法。

另一种方法是使用 Visual Studio Express 2008 中的 XML 编辑器。如果您为它提供架构,它不仅会验证 XML,还会提供 IntelliSense - 它会显示有效的下一个元素或属性,甚至会显示包含架构文档的工具提示。


没有办法做你正在寻找的东西。您提到的许多这些语义失败将在序列化过程的某个深处显示为异常。这些异常中的第一个将终止该过程。您只能在调用XmlSerializer.DeSerialize 之外捕获此类异常。到那时,任何上下文都消失了,你所拥有的只是 Exception.InnerException.InnerException 的链......

如果您通过实现IXmlSerializable 进行自己的反序列化,那么您将能够将异常处理保留在类中,并可以访问正在使用的 XmlReader。如果该阅读器维护行和列信息,那么您应该能够将该信息添加到异常中。

【讨论】:

  • 请参阅我的说明。这些错误被检测到很晚,并且不可能在编辑时在用户界面中检测到,或者在读取时使用任何类型的验证逻辑。
  • 如果我必须在任何时候实现IXmlSerializable 来获取此类信息,那么我不妨将XML 序列化完全用于此用例。无论如何,我终于开始需要这样做了。
【解决方案2】:

这篇关于 XML 序列化故障排除的 MSDN 文章可能会有所帮助 -- http://msdn.microsoft.com/en-us/library/aa302290.aspx 它表明:

就像在 序列化,Deserialize() 方法抛出 InvalidOperation 消息异常

There is an error in XML document
(<line>, <column>).

每当出现问题时。这个 异常通常包含真正的 InnerException 中的异常 财产。的类型 InnerException 因 发生的实际错误,而 读取 XML 文档。

澄清 - 如果您可以在反序列化期间导致对象自我验证并失败,这将是在您拥有所有上下文时获取问题位置的最佳方法。

【讨论】:

  • 反序列化过程中无法检测到错误,数据必须保存在最终的对象图中,以便以后运行时错误报告。
【解决方案3】:

我正在为包含错误的对象生成 XPath,然后使用 XDocument 找到相应的 XML 元素。

public static int GetLineNumber(XDocument document, string xPath) 
{
        var xmlNamespaceManager = new XmlNamespaceManager(new NameTable());
        xmlNamespaceManager.AddNamespace("myns", "http://myns.com");
        var xPathEvaluate = document.XPathSelectElement(xPath, xmlNamespaceManager);
        return ((IXmlLineInfo)xPathEvaluate).LineNumber;
}

这不是很有效的做法。如果有人知道找到反序列化对象行号的更好方法,请写在 cmets 中。

【讨论】:

  • XPath API 不适用于 Compact Framework。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-10
  • 2011-07-12
相关资源
最近更新 更多