解析具有未定义实体的 XHTML 文档

问题描述 投票:0回答:4

在使用 Python 编码时,如果我必须加载带有未定义实体的 XHTML 文档,我将创建一个解析器并更新实体字典(即

nbsp
):

import xml.etree.ElementTree as ET
parser = ET.XMLParser()
parser.entity['nbsp'] = ' '
tree = ET.parse(opener.open(url), parser=parser)

使用 VB.Net,我尝试将 XHTML 文档解析为 Linq XDocument:

Dim x As XDocument = XDocument.Load(url)

引发了 XmlException:

引用未声明的实体'nbsp'

谷歌搜索我找不到任何示例如何更新实体表或使用简单的方法来解析具有未定义实体的 XHTML 文档。

如何解决这个看似简单的问题?

.net xml vb.net xhtml
4个回答
3
投票

实体解析由底层解析器完成,这里是标准的

XmlReader
(或
XmlTextReader
)。

正式地说,您应该在 DTD 中声明实体(参见 Oleg 的回答:XHTML 实体问题),或者将 DTD 动态加载到您的文档中。这里有一些这样的例子:How do I resolve entities when loading into an XDocument?

你还可以做的是创建一个 hacky

XmlTextReader
派生类,它在检测到实体时返回
Text
节点,基于字典,就像我在下面的示例代码中演示的那样:

using (XmlTextReaderWithEntities reader = new XmlTextReaderWithEntities(MyXmlFile))
{
    reader.AddEntity("nbsp", "\u00A0");
    XDocument xdoc = XDocument.Load(reader);
}

...

public class XmlTextReaderWithEntities : XmlTextReader
{
    private string _nextEntity;
    private Dictionary<string, string> _entities = new Dictionary<string, string>();

    // NOTE: override other constructors for completeness
    public XmlTextReaderWithEntities(string path)
        : base(path)
    {
    }

    public void AddEntity(string entity, string value)
    {
        _entities[entity] = value;
    }

    public override bool Read()
    {
        if (_nextEntity != null)
            return true;

        return base.Read();
    }

    public override XmlNodeType NodeType
    {
        get
        {
            if (_nextEntity != null)
                return XmlNodeType.Text;

            return base.NodeType;
        }
    }

    public override string Value
    {
        get
        {
            if (_nextEntity != null)
            {
                string value = _nextEntity;
                _nextEntity = null;
                return value;
            }
            return base.Value;
        }
    }

    public override void ResolveEntity()
    {
        // if not found, return the string as is
        if (!_entities.TryGetValue(LocalName, out _nextEntity))
        {
            _nextEntity = "&" + LocalName + ";";
        }
        // NOTE: we don't use base here. Depends on the scenario
    }
}

这种方法适用于简单的场景,但为了完整性,您可能需要覆盖一些其他内容。

PS:抱歉它在 C# 中,您必须适应 VB.NET :)


1
投票

我还没有这样做,但是你可以创建一个

XmlParserContext
对象,其所需的实体声明为
internalSubset
。将该上下文传递给构造函数中的
XmlTextReader
,并通过加载读取器来创建
XDocument
对象。在 MSDN 中已经有一个看起来简单的 example code snippet in VB for using a pre-defined entity.


0
投票

在这种情况下,我假设您在网络上访问了一个页面,因此您可以使用可以满足您需要的 html 敏捷包。

我使用 xpath、element 和更多其他东西。搜索 html 页面等非常有用

您可以在这里找到文档:htmlagilitypack


0
投票

在python3.4+中,您可以使用

html.unescape
将html5实体引用转换为相应的unicode字符。之后,任何 xml 解析器都可以工作。

from html import escape, unescape
textXML = re.sub("\\&\\w+\\;", lambda x: escape(unescape(x.group(0))), text)
© www.soinside.com 2019 - 2024. All rights reserved.