首页 > 解决方案 > Java XML 解析器添加了不必要的 xmlns 和 xml:space 属性

问题描述

我在 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规范表明默认情况下 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。(请参阅如何从 Java XML DOM 中的 DTD 强制删除具有隐含默认值的属性。)但这非常低效;在解析时完全关闭它会很好。

标签: javaxmlxml-parsingxml-namespacesdtd

解决方案


您是否尝试过nonvalidating/load-dtd-grammarXerces 配置功能?

但是,我一直在研究如何在 Saxon 中执行此操作,并且我不会要求 XML 解析器不报告默认属性,而是在报告默认属性时将其丢弃。我使用 Xerces 作为 SAX 解析器而不是 DOM 解析器。(在 SAX 中,使用 报告默认属性Attributes2.isDefaulted())。


推荐阅读