使用 System.Xml.XmlReader,解析 DTD如果存在但如果不存在则不会失败

问题描述

我想解析可能有也可能没有 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,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,String baseUriString,XmlParserContext inputContext)
   at System.Xml.XmlReader.Create(Stream input,XmlParserContext inputContext)

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

我怀疑这可能与 XmlParserContext 有关(考虑到堆栈跟踪中的此功能),但我不知道如何初始化 XmlParserContext,因为我不知道提前知道文档中的内容。我提供了一个 XmlParserContext,其中没有为 docTypeName 提供值。

解决方法

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

我现在正在创建一个这样的解析器,无论是否有 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 的方法,因此我使用自己的 XmlResolver 知道基 URI,并使用它代替提供给 XmlResolver 的 { {1}} 方法。

我观察到的失败原因如下:

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...