我需要将XHTML5文件解析为XDocument
个实例。我的文件将始终是格式良好的XML,因此我希望避免使用HtmlAgilityPack,因为它存在格式错误的XHTML。 XDocument.Load
方法适用于简单情况,但在文档包含命名字符引用(实体)时中断:
var xhtml = XDocument.Load(reader);
// XmlException: Reference to undeclared entity 'nbsp'.
对于XHTML 1.0,可以使用XmlPreloadedResolver
解决此问题,该this answer预加载XHTML 1.0中定义的众所周知的DTD。可以通过手动提供其DTD来扩展该方法以支持XHTML 1.1,如this other answer所示。
但是,XHTML5没有DTD,正如as JSON中所讨论的那样。其实体定义仅供参考providing XmlReader
with a list of entity declarations。
<!DOCTYPE html>
因此,在XHTML5中解析实体时,永远不会调用XmlResolver
方法。讨论了is allowed的尝试,但似乎没有任何方法可以开箱即用。
目前,我正在研究两种方法。第一种是通过源XHTML上的字符串操作或通过XmlParserContext.InternalSubset
在文档类型声明中指定具有实体声明的内部子集。这将导致文档类型声明类似于:
<!DOCTYPE html [
<!ENTITY ndash "–">
<!ENTITY nbsp " ">
...
]>
在XHTML5中似乎是这个more than 2000;然而,它是不受欢迎的,因为它使用实体声明(现在有this answer)来填充XDocument
,如果用户将其转换回字符串表示,这将是有问题的。
我的另一种方法是使用regex预处理XHTML字符串,将所有命名的字符引用转换为数字字符引用(或实际的Unicode字符),不包括XML预定义实体" & ' < >
。但是,我担心这种方法可能会错过XML定义的复杂性。例如,表示不得在注释,CDATA部分或处理说明中转义字符。我假设我的正则表达式需要调整以排除所有这些事件。
有没有人对这两种方法或您考虑的任何其他方法有经验或建议?我更喜欢基于XmlReader
的可扩展性构建的方法,但如果没有其他方法,则会采用源字符串操作。
答案 0 :(得分:1)
如果您使用实体地图将身份转换应用于源文档,它将在结果中替换您的实际字符。对我来说,这与正则表达式没有什么不同(一步),当然也不那么复杂。
鉴于此来源:
<!DOCTYPE foo [
<!ENTITY ndash "–">
<!ENTITY nbsp " ">
]>
<foo>
<p>I am – and I am non-breaking space.</p>
</foo>
这个转变:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
您可以将此结果作为新输入:
<foo>
<p>I am – and I am non-breaking space.</p>
</foo>
此外,您可以将所有这些定义保存在单独的文件中,并像这样添加一个引用:
<!ENTITY % winansi SYSTEM "path/to/my/map/winansi.xml"> %winansi;]>