Как легко изменить тип документа XML-документа в Java?
Вопрос
Вот моя проблема:
Моя программа получает на вход XML-файлы.Эти файлы могут иметь или не иметь декларацию XML, декларацию типа документа или декларацию сущности, но все они соответствуют одной и той же схеме.Когда моя программа получает новый файл, ей необходимо проверить его и убедиться, что в нем есть такие объявления:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE my.doctype [
<!ENTITY % entity_file SYSTEM "my.entities.ent">
%entity_file;
]>
Если это есть, это здорово, и я могу оставить их как есть, но если объявления отсутствуют или неверны, мне нужно удалить все, что уже есть, и добавить правильные объявления.
Как я могу это сделать (желательно легко, используя стандартные библиотеки Java 6 и/или Apache)?
Решение
Зачем вам «удалять все, что уже есть, и добавлять правильные объявления»?
Если вы используете XML-файл для ввода и не записываете его обратно в той или иной форме, то подходящим решением будет создание файла EntityResolver
.
Полное описание процесса есть здесь, но следующий код показывает, как предоставить синтаксическому анализатору собственное DTD, независимо от того, что ему нужно в документе:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(true);
DocumentBuilder db = dbf.newDocumentBuilder();
db.setEntityResolver(new EntityResolver()
{
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException
{
return new InputSource(new StringReader(dtd));
}
});
Другие советы
Этот код должен помочь вам разобраться в этом.Возможно, вам придется создать новый документ, чтобы изменить содержимое типа документа, если он неправильный. Я не знаю, как изменить существующий.
private Document copyDocument(Document document) {
DocumentType origDoctype = document.getDoctype();
DocumentType doctype = documentBuilder
.getDOMImplementation().createDocumentType(origDoctype.getName(),
origDoctype.getPublicId(),
origDoctype.getSystemId());
Document copiedDoc = documentBuilder.getDOMImplementation().
createDocument(null, origDoctype.getName(), doctype);
// so we already have the top element, and we have to handle the kids.
Element newDocElement = copiedDoc.getDocumentElement();
Element oldDocElement = document.getDocumentElement();
for (Node n = oldDocElement.getFirstChild(); n != null; n = n.getNextSibling()) {
Node newNode = copiedDoc.importNode(n, true);
newDocElement.appendChild(newNode);
}
return copiedDoc;
}
Если у вас есть контроль над тем, как формируются эти документы, старайтесь избегать DTD, поскольку они вносят ненужную сложность и недостаточны для выражения схемы...