Я работаю в системе, которая должна иметь возможность читать любой (или, по крайней мере, любой правильно сформированный) XML-файл, манипулировать несколькими узлами и записывать их обратно в тот же файл. Я хочу, чтобы мой код был как можно более универсальным, и я не хочу
- жестко закодированные ссылки на информацию о схеме / доктрине в любом месте моего кода. Информация о типе документа находится в исходном документе, я хочу сохранить именно эту информацию о типе документа и не предоставлять ее снова из моего кода. Если документ не имеет DocType, я не буду его добавлять. Меня не волнует форма или содержимое этих файлов, за исключением нескольких моих узлов.
- пользовательские EntityResolvers или StreamFilters для пропуска или иного манипулирования исходной информацией (Жаль, что информация о пространстве имен кажется каким-то недоступной из файла документа, в котором она объявлена, но я могу управлять с помощью более уродливых XPaths)
- Проверка DTD. У меня нет ссылочных DTD, я не хочу их включать, и манипулирование Node вполне возможно, не зная о них.
Цель состоит в том, чтобы исходный файл был полностью неизменным, за исключением измененных узлов, которые извлекаются через XPath. Я хотел бы уйти со стандартным материалом javax.xml.
Мой прогресс до сих пор:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setAttribute("http://xml.org/sax/features/namespaces", true);
factory.setAttribute("http://xml.org/sax/features/validation", false);
factory.setAttribute("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
factory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setNamespaceAware(true);
factory.setIgnoringElementContentWhitespace(false);
factory.setIgnoringComments(false);
factory.setValidating(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(inStream));
Это успешно загружает источник XML в org.w3c.dom.Document, игнорируя проверку DTD. Я могу сделать свои замены, а затем я использую
Source source = new DOMSource(document);
Result result = new StreamResult(getOutputStream(getPath()));
// Write the DOM document to the file
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(source, result);
чтобы написать обратно. Что почти идеально. Но тег Doctype пропал, что бы я ни делал. Во время отладки я обнаружил, что в объекте Document после синтаксического анализа есть объект DeferredDoctypeImpl [log4j: configuration: null], но он почему-то неверный, пустой или игнорируется. Файл, на котором я тестировал, начинается примерно так (но он одинаков для других типов файлов):
<? Xml version = "1.0" encoding = "UTF-8"?>
<! DOCTYPE log4j: настройка системы "log4j.dtd">
[...]
Я думаю, что есть много (простых?) Способов вовлечения хаков или добавления дополнительных JAR-файлов в проект. Но я бы хотел иметь его с теми инструментами, которые я уже использую.