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

Using System.Xml.XmlReader, parse the DTD if present but don't fail if absent

我想解析 XML 可能有也可能没有 DTD 的文档。如果有 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.

提供值

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

我现在正在创建这样的解析器,无论是否有 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 的 ResolveUri 方法。

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

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

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