Java XML解析器添加了不必要的xmlns和xml:space属性

问题描述 投票:1回答:2

[我正在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。)但这效率很低;最好在解析时完全关闭此功能。

java xml xml-parsing xml-namespaces dtd
2个回答
0
投票

我发现了一种解决方法,尽管它并不理想。这个想法是,当文档要求使用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);

[有点像混战,从语义上讲,我不喜欢它。但是对于我的应用程序,我只需要一个干净且格式正确的分析文档,并带有正确的实体替换,因此在实践中,它对于大多数文档可能会产生相同的结果。


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.