【发布时间】:2020-04-03 00:26:34
【问题描述】:
我在 Windows 10 上使用 Java 11 (AdoptOpenJDK 11.0.5 2019-10-15)。我正在解析一些旧的 XHTML 1.1 文件,这些文件采用以下一般形式:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" http://www.w3.org/MarkUp/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>XHTML 1.1 Skeleton</title>
</head>
<body>
</body>
</html>
我正在使用一个简单的非验证解析器:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
final Document document;
try (InputStream inputStream = new BufferedInputStream(getClass().getResourceAsStream("xhtml-1.1-test.xhtml"))) {
document = documentBuilder.parse(inputStream);
}
由于某种原因,它在各处添加了额外的属性,例如 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 和 xml:space="preserve":
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" version="-//W3C//DTD XHTML 1.1//EN" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:lang="en">
<head xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<title xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">XHTML 1.1 Skeleton</title>
</head>
<body xmlns="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xml:space="preserve"></body>
</html>
我知道 DTD 可以提供默认属性值,但我不明白为什么要添加 xmlns:xsi 属性,而该名称空间中似乎没有元素或属性。
此外,xml:space="preserve" 似乎完全不正确;我想只有像<pre> 这样的元素应该设置xml:space="preserve"。 (更新:HTML5 specification 表示默认情况下 HTML 会保留空间,并且 xml:space 不能在 HTML 中序列化,所以这可能是这里的部分原因。我将改进我的 HTML 序列化器忽略xml:space 属性,这将部分缓解此问题。)
还要注意version="-//W3C//DTD XHTML 1.1//EN";那是我不需要或不想要的东西。
我做错了吗?有没有办法可以将解析器配置为不包含这些不必要的内容?
有趣的是,这不是 XHTML 1.0 strict 的问题。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>XHTML 1.0 Skeleton</title>
</head>
<body>
</body>
</html>
当解析得到预期结果时:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>XHTML 1.0 Skeleton</title>
</head>
<body>
</body>
</html>
但这是-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN 的问题。所以这似乎只是一个 XHTML 1.1 问题。
更新: 我有一些可能有用的消息:如果我创建一个没有 DTD 的新文档并将整个文档树导入到新文档中,那么所有这些内容(显然来自DTD) 消失了,因为目标文档根本没有 DTD。 (请参阅How to force removal of attributes with implied default values from DTD in Java XML DOM。)但这非常低效;解析时最好完全关闭它。
【问题讨论】:
-
什么是
DefaultEntityResolver?另外,关于“由于某种原因它添加了额外的属性”,你的意思是它被添加到原始的 xml 文件中吗?如果没有,如何将Document对象转换为 XML 字符串(或将其保存到文件中)? -
DefaultEntityResolver是一个实体解析器,它在本地提供实体(例如 DTD),而不是从 Internet 下载它们。如果要验证实体的内容,请参阅票证 globalmentor.atlassian.net/browse/JAVA-175 或克隆提交 bitbucket.org/globalmentor/…。 -
当我说“出于某种原因它添加了额外的属性”时,我的意思是它正在将它们添加到 DOM 树中。我正在使用我自己编写的自定义 XML 序列化程序来打印树。
-
如果删除 DefaultEntityResolver 会发生什么?
-
如果我删除了
DefaultEntityResolver,那么它甚至不会解析,并且因为java.io.FileNotFoundExceptionforhttp://www.w3.org/TR/xhtml11/DTD/xhtml-datatypes-1.mod而崩溃。显然,W3C 已经从其网站上完全删除了这个实体。 (那么现在没有人使用标准的 Java XML 解析器解析 XHTML 1.1 文件了吗?这完全被破坏了。)所以我必须使用自定义实体解析器来处理本地存储的实体,否则它甚至不会解析。 @Olivier 你自己试过了吗?
标签: java xml xml-parsing xml-namespaces dtd