【问题标题】:Using System.Xml.XmlReader, parse the DTD if present but don't fail if absent使用 System.Xml.XmlReader,如果存在则解析 DTD,但如果不存在则不会失败
【发布时间】:2021-06-02 11:41:02
【问题描述】:

我想解析可能有也可能没有 DTD 的 XML 文档。如果有 DTD,那么我想用它来扩展实体引用。如果没有 DTD(更严格地说,如果没有 DOCTYPE 声明),我只想忽略 DTD 处理。

当我设置XmlReaderSettings.DtdProcessing=Ignore 时,包含实体引用的文档解析失败,因为该实体被视为未声明。

当我设置 XmlReaderSettings.DtdProcessing=Parse 时,解析没有 DOCTYPE 声明的文档会失败,诊断结果相当模糊:

The empty string '' is not a valid name. (Parameter 'docTypeName')
System.ArgumentException: The empty string '' is not a valid name. (Parameter 'docTypeName')
   at System.Xml.DtdParser.InitializeFreeFloatingDtd(String baseUri, String docTypeName, String publicId, String systemId, String internalSubset, IDtdParserAdapter adapter)
   at System.Xml.DtdParser.System.Xml.IDtdParser.ParseFreeFloatingDtd(String baseUri, String docTypeName, String publicId, String systemId, String internalSubset, IDtdParserAdapter adapter)
   at System.Xml.XmlTextReaderImpl.ParseDtdFromParserContext()
   at System.Xml.XmlTextReaderImpl.ProcessDtdFromParserContext(XmlParserContext context)
   at System.Xml.XmlTextReaderImpl.FinishInitStream()
   at System.Xml.XmlTextReaderImpl..ctor(Stream stream, Byte[] bytes, Int32 byteCount, XmlReaderSettings settings, Uri baseUri, String baseUriStr, XmlParserContext context, Boolean closeInput)
   at System.Xml.XmlReaderSettings.CreateReader(Stream input, Uri baseUri, String baseUriString, XmlParserContext inputContext)
   at System.Xml.XmlReader.Create(Stream input, XmlReaderSettings settings, XmlParserContext inputContext)

是否有任何设置可以处理这两种情况,还是我需要先查看内容并相应地设置解析器?

我怀疑这可能与 XmlParserContext 有关(鉴于堆栈跟踪上的此功能),但我不知道如何初始化 XmlParserContext,因为我不知道里面有什么提前文件。我提供了一个XmlParserContext,其中没有为docTypeName 提供任何值。

【问题讨论】:

  • 如果性能不是问题,如果Parse 失败,您可以尝试Ignore
  • 您是否尝试过不使用 XmlParserContext 参数?
  • 我已经深入研究了我设置 DtdProcessing=Parse 的情况,但它仍然没有解析实体引用,所以我还缺少其他东西。
  • @Dialectus 这将是一个可怕的最后手段。偷看输入流可能是一个较小的邪恶,但仍然很可怕。
  • 你也可以先试试Prohibit。它会在解析过程的早期失败,并提供更多有用的文本,如果失败则使用ParseProhibit 帮你偷看。

标签: c# xml dtd


【解决方案1】:

好的,我想我已经解决了。我走了许多错误的线索,有些是我自己制造的,有些是由糟糕的文档引发的。

我现在正在创建这样的解析器,无论是否有 DOCTYPE 声明:

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024;
settings.XmlResolver = new MyXmlResolver(new Uri(source.getSystemId()));
xmlReader = XmlReader.Create(inputStream, settings);

不需要XmlParserContext 对象,它似乎只是碍事(我仍然不知道它的真正作用)。

我没有找到同时为解析器提供输入流和基本 URI 的方法,所以我改用我自己的知道基本 URI 的 XmlResolver,并使用它代替提供给 XmlResolver 的 @ 987654323@方法。

我观察到的故障原因如下:

(a) System.ArgumentException 是由我尝试提供 XmlParserContext 引起的,当我切换到不使用的构造函数时它消失了。 (谢谢,@jdweng)。

(b) “实体未声明”错误是由于无法解析 DTD 系统 ID 的静默失败引起的,而这又是由于我没有找到任何成功的方法来为解析器提供基本 URI(我尝试使用 XmlParserContext 来执行此操作,但事实证明这是错误的)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-16
    • 2019-08-20
    • 1970-01-01
    • 2016-05-15
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 2013-05-08
    相关资源
    最近更新 更多