Java XML парсер, добавляющий ненужные xmlns и xml: атрибуты пробела - PullRequest
3 голосов
/ 09 марта 2020

Я использую Java 11 (AdoptOpenJDK 11.0.5 2019-10-15) на Windows 10. Я анализирую некоторые устаревшие файлы X HTML 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"; это то, что мне не нужно или не нужно.

Я что-то не так делаю? Есть ли способ настроить парсер так, чтобы он не включал этот ненужный код?

Интересно, что это не проблема со строгим X HTML 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. Так что, похоже, это просто проблема X HTML 1.1.

Обновление: У меня есть несколько потенциально полезных новостей: если я создаю новый документ без DTD и импортирую все дерево документов в новый документ все это бессмысленно (что, очевидно, исходит из подразумеваемых атрибутов в DTD) исчезает, потому что у целевого документа вообще нет DTD. (См. Как принудительно удалить атрибуты с подразумеваемыми значениями по умолчанию из DTD в Java XML DOM .) Но это очень неэффективно; было бы неплохо вообще отключить это при разборе.

Ответы [ 2 ]

0 голосов
/ 16 марта 2020

Вы пробовали использовать функцию конфигурации nonvalidating/load-dtd-grammar Xerces?

Однако я только что посмотрел, как мне это сделать в Saxon, и я не прошу парсер XML не сообщать об атрибутах по умолчанию, скорее я их отбрасываю, когда они сообщаются. Я использую Xerces как SAX-парсер, а не DOM-парсер. (В SAX атрибуты по умолчанию сообщаются с использованием Attributes2.isDefaulted()).

0 голосов
/ 15 марта 2020

Я нашел обходной путь, хотя он не идеален. Идея состоит в том, что, когда документ запрашивает анализ с помощью DTD -//W3C//DTD XHTML 1.1//EN X HTML 1.1, вместо него действительно используется строгий DTD -//W3C//DTD XHTML 1.0 Strict//EN X HTML 1.0. Для большинства практических целей это DTD фактически почти то же самое , что и запрашиваемое ими, но оно не включает в себя все по умолчанию.

Помня, что DefaultEntityResolver - моя сущность распознаватель с большинством предопределенных DTD X HTML (см. полный список модулей X HTML, MathML и SVG и других сущностей с идентификаторами publi c? ), реализация выглядит примерно так this:

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);

Это что-то вроде клочья, и семантически мне это не нравится. Но для моего приложения мне просто нужен чистый, правильно сформированный разобранный документ с правильной заменой сущностей, поэтому на практике он может дать практически одинаковые результаты для большинства документов.

...