[我正在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"
。 (也请注意version="-//W3C//DTD XHTML 1.1//EN"
;这是我不需要或想要的。)
我做错什么了吗?有没有一种方法可以将解析器配置为不包含此不必要的杂项?
有趣的是,对于XHTML 1.0严格来说这不是问题。
<?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问题。
Update:我有一些可能有用的消息:如果我创建一个没有DTD的新文档并将整个文档树导入到新文档中,那么所有这些杂项(显然来自DTD中的隐含属性)就会消失离开,因为目标文档根本没有DTD。 (请参阅How to force removal of attributes with implied default values from DTD in Java XML DOM。)但这效率很低;最好在解析时完全关闭此功能。
我发现了一种解决方法,尽管它并不理想。这个想法是,当文档要求使用XHTML 1.1 DTD -//W3C//DTD XHTML 1.1//EN
进行解析时,实际上是使用XHTML 1.0 Strict DTD -//W3C//DTD XHTML 1.0 Strict//EN
。出于大多数实际目的,此DTD是他们要求的DTD effectively almost the same,但它并未包含所有默认值。
[记住DefaultEntityResolver
是我的实体解析器,并且预定义了大多数XHTML DTD(请参阅Complete list of XHTML, MathML, and SVG modules and other entities, with public identifiers?,实现看起来像这样:
private static final EntityResolver XHTML_1_1_TO_XHTML_1_0_ENTITY_RESOLVER = new EntityResolver() { private final EntityResolver defaultEntityResolver = DefaultEntityResolver.getInstance(); @Override public InputSource resolveEntity(final String publicID, final String systemID) throws SAXException, IOException { if(XHTML_1_1_PUBLIC_ID.equals(publicID)) { final InputSource inputSource = resolveEntity(XHTML_1_0_STRICT_PUBLIC_ID, systemID); inputSource.setPublicId(publicID); return inputSource; } return defaultEntityResolver.resolveEntity(publicID, systemID); } };
然后我在解析时会使用该实体解析器:
documentBuilder.setEntityResolver(XHTML_1_1_TO_XHTML_1_0_ENTITY_RESOLVER);
[有点像混战,从语义上讲,我不喜欢它。但是对于我的应用程序,我只需要一个干净且格式正确的分析文档,并带有正确的实体替换,因此在实践中,它对于大多数文档可能会产生相同的结果。
您是否尝试过nonvalidating/load-dtd-grammar
Xerces配置功能?