在我的S1000D xml中,它指定DOCTYPE,并带有对公共URL的引用,该URL包含对许多其他文件的引用,这些文件包含所有有效字符实体。我已经使用xml.etree.ElementTree和lxml尝试对其进行解析,并得到一个解析错误,两者均指示:
undefined entity −: line 82, column 652
即使−
是根据指定的ENTITY参考的有效实体。
xml顶部如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dmodule [
<!ENTITY % ISOEntities PUBLIC 'ISO 8879-1986//ENTITIES ISO Character Entities 20030531//EN//XML' 'http://www.s1000d.org/S1000D_4-1/ent/ISOEntities'>
%ISOEntities;]>
如果您出去获取http://www.s1000d.org/S1000D_4-1/ent/ISOEntities,它将包含其他20个ent文件,其中一个名为iso-tech.ent,其中包含以下行:
<!ENTITY minus "−"> <!-- MINUS SIGN -->
是以下内容:
....请参阅70 −
41 ....
如何在不获取未定义实体的情况下运行python脚本来解析此文件?
抱歉,我不想指定parser.entity['minus'] = chr(2212)
。我这样做是为了快速解决问题,但是有很多字符实体引用。
我希望解析器检查xml中指定的实体引用。
我很惊讶,但是我已经绕着太阳转了转,还没有找到如何做的办法(或者也许我已经做到了,但是却无法遵循)。
如果我更新xml文件并添加
<!ENTITY minus "−">
它不会失败,所以它不是xml。
解析失败。这是我用于ElementTree的代码
fl = os.path.join(pth, fn)
try:
root = ET.parse(fl)
except ParseError as p:
print("ParseError : ", p)
这是我用于lxml的代码
fl = os.path.join(pth, fn)
try:
parser = etree.XMLParser(load_dtd=True, resolve_entities=True)
root = etree.parse(fl, parser=parser)
except etree.XMLSyntaxError as pe:
print("lxml XMLSyntaxError: ", pe)
我希望解析器加载ENTITY引用,以便它知道-以及在所有文件中指定的所有其他字符实体都是有效的实体字符。
非常感谢您的建议和帮助。
答案 0 :(得分:2)
我要回答lxml。如果可以使用lxml,没有理由考虑使用ElementTree。
我认为您缺少的部分是XMLParser中的no_network=False
;是True by default。
示例...
XML输入(test.xml)
<!DOCTYPE doc [
<!ENTITY % ISOEntities PUBLIC 'ISO 8879-1986//ENTITIES ISO Character Entities 20030531//EN//XML' 'http://www.s1000d.org/S1000D_4-1/ent/ISOEntities'>
%ISOEntities;]>
<doc>
<test>Here's a test of minus: −</test>
</doc>
Python
from lxml import etree
parser = etree.XMLParser(load_dtd=True,
no_network=False)
tree = etree.parse("test.xml", parser=parser)
etree.dump(tree.getroot())
输出
<doc>
<test>Here's a test of minus: −</test>
</doc>
如果要保留实体引用,请将resolve_entities=False
添加到XMLParser。
也可以考虑设置一个XML Catalog,而不是去外部解析参数实体。这将使您可以将公共和/或系统标识符解析为本地版本。
示例使用与上面相同的XML输入...
XML目录(“目录测试”目录中的“ catalog.xml”(用于测试的目录名中的空间))
<!DOCTYPE catalog PUBLIC "-//OASIS//DTD XML Catalogs V1.1//EN" "http://www.oasis-open.org/committees/entity/release/1.1/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<!-- The path in @uri is relative to this file (catalog.xml). -->
<uri name="http://www.s1000d.org/S1000D_4-1/ent/ISOEntities" uri="./ents/ISOEntities_stackoverflow.ent"/>
</catalog>
实体文件(目录“ catalog test / ents”中的“ ISOEntities_stackoverflow.ent”。将值更改为“ BAM!”进行测试)
<!ENTITY minus "BAM!">
Python (将no_network
的{{1}}更改为True
,以获取使用本地版本http://www.s1000d.org/S1000D_4-1/ent/ISOEntities
的更多证据。)
import os
from urllib.request import pathname2url
from lxml import etree
# The XML_CATALOG_FILES environment variable is used by libxml2 (which is used by lxml).
# See http://xmlsoft.org/catalog.html.
try:
xcf_env = os.environ['XML_CATALOG_FILES']
except KeyError:
# Path to catalog must be a url.
catalog_path = f"file:{pathname2url(os.path.join(os.getcwd(), 'catalog test/catalog.xml'))}"
# Temporarily set the environment variable.
os.environ['XML_CATALOG_FILES'] = catalog_path
parser = etree.XMLParser(load_dtd=True,
no_network=True)
tree = etree.parse("test.xml", parser=parser)
etree.dump(tree.getroot())
输出
<doc>
<test>Here's a test of minus: BAM!</test>
</doc>