3

当我尝试使用 XDocument 解析以下数据时,出现以下错误:

“XMLException:内部标记中不允许参数实体引用”

这是我试图解析的示例数据:

<!DOCTYPE sgml [
  <!ELEMENT sgml ANY>
  <!ENTITY % std       "standard SGML">
  <!ENTITY % signature " &#x2014; &author;.">
  <!ENTITY % question  "Why couldn&#x2019;t I publish my books directly in %std;?">
  <!ENTITY % author    "William Shakespeare">
]>
<sgml>&question;&signature;</sgml>

这是尝试解析上述文件的代码:

string caFile = @"pathToFile";
using (var caStream = File.Open(caFile, FileMode.Open, FileAccess.Read))
{
    var caDoc = XDocument.Load(caStream); // Exception thrown here!
}

有没有办法让内置的 .NET xml 解析库来处理实体引用,或者至少忽略嵌入的 !Doctype 并解析根元素?

注意:我假设参数实体引用在 XML 中有效。(见这里

4

1 回答 1

1

这里有一些问题,但主要是看起来你应该使用通用实体

  1. 您将实体定义为参数实体。这些基本上是只在 DTD 内部使用的宏。从XML 规范

    参数实体引用不得出现在 DTD 之外。

    XML in a Nutshell 2nd Edition

    最好定义一个常量,该常量可以保存所有五种列表的内容规范的公共部分,并从每个元素的内容规范内部引用该常量。...

    实体引用是这里的明显候选者。但是,一般实体引用不允许为内容规范或属性列表提供替换文本,只能用于将包含在 XML 文档本身中的部分 DTD。相反,XML 提供了一个专门用于 DTD 内部的新构造,即参数实体,由参数实体引用引用。参数实体的行为和声明几乎完全像一般实体。但是,它们使用 % 而不是 &,并且它们只能在 DTD 中使用,而一般实体只能在文档内容中使用。

    但是,您的 XML 指的是其文档内容中的实体。这表明您应该使用通用实体而不是参数实体。

  2. 您的一个参数实体,在其替换文本中%question嵌入了对另一个参数实体 的引用。XML 规范%std;明确不允许这样做:

    在内部 DTD 子集中,参数实体引用不得出现在标记声明中;它们可能发生在可以发生标记声明的地方。(这不适用于出现在外部参数实体或外部子集中的引用。)

    再次看来,您应该使用通用实体而不是参数实体,因为前者可以“在 DTD 内部的地方使用,它们最终将包含在 XML 文档的正文中,例如……在另一个的替换文本中实体。”

  3. 您需要通过设置XmlReaderSettings.ProhibitDtd = false(.Net 3.5)或XmlReaderSettings.DtdProcessing = DtdProcessing.Parse(更高版本)来启用 D​​TD 处理。

把这些放在一起,下面的代码:

    string xmlGood = @"<!DOCTYPE sgml [
  <!ELEMENT sgml ANY>
  <!ENTITY std       ""standard SGML"">
  <!ENTITY signature "" &#x2014; &author;."">
  <!ENTITY question  ""Why couldn&#x2019;t I publish my books directly in &std;?"">
  <!ENTITY author    ""William Shakespeare"">
]>
<sgml>&question;&signature;</sgml>";

    var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse };

    using (var sr = new StringReader(xmlGood))
    using (var xmlReader = XmlReader.Create(sr, settings))
    {
        var doc = XDocument.Load(xmlReader);
        Console.WriteLine(doc);
    }               

产生以下输出:

<!DOCTYPE sgml [
  <!ELEMENT sgml ANY>
  <!ENTITY std       "standard SGML">
  <!ENTITY signature " — &author;.">
  <!ENTITY question  "Why couldn’t I publish my books directly in &std;?">
  <!ENTITY author    "William Shakespeare">
]>
<sgml>Why couldn’t I publish my books directly in standard SGML? — William Shakespeare.</sgml>

如您所见,一般实体已被解析和扩展。

于 2015-05-29T17:53:22.293 回答