Как бороться с неизвестными ссылками на сущности? - PullRequest
8 голосов
/ 12 марта 2010

Я анализирую (много) XML-файлов, которые содержат ссылки на сущности, которые я не знаю заранее (не могу изменить этот факт).

Например:

xml = "<tag>I'm content with &funny; &entity; &references;.</tag>"

когда я пытаюсь разобрать это, используя следующий код:

final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
final DocumentBuilder db = dbf.newDocumentBuilder();
final InputSource is = new InputSource(new StringReader(xml));
final Document d = db.parse(is);

я получаю следующее исключение:

org.xml.sax.SAXParseException: The entity "funny" was referenced, but not declared.

но я хочу, чтобы парсер заменял каждую сущность, которая не объявлена ​​(неизвестна парсеру), пустой строкой ''. Или даже лучше, есть ли способ передать карту в парсер, например:

Map<String,String> entityMapping = ...
entityMapping.put("funny","very");
entityMapping.put("entity","important");
entityMapping.put("references","stuff");

чтобы я мог сделать следующее:

final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
final DocumentBuilder db = dbf.newDocumentBuilder();
final InputSource is = new InputSource(new StringReader(xml));

db.setEntityResolver(entityMapping);
final Document d = db.parse(is);

если бы я получил текст из документа, используя этот пример кода, я должен получить:

I'm content with very important stuff.

Есть предложения? Конечно, я уже был бы рад просто заменить неизвестную сущность пустыми строками.

Спасибо

Ответы [ 3 ]

3 голосов
/ 16 марта 2010

StAX API имеет поддержку для этого. Взгляните на XMLInputFactory , у него есть свойство времени выполнения , которое определяет, будут ли внутренние сущности расширены или оставлены на месте. Если установлено значение false, тогда поток событий StAX будет содержать экземпляры EntityReference для представления нерасширенных объектов.

Если вы все еще хотите DOM в качестве конечного результата, вы можете связать его вместе, как показано ниже:

XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
Transformer transformer = TransformerFactory.newInstance().newTransformer();

String xml = "my xml";
StringReader xmlReader = new StringReader(xml);
XMLEventReader eventReader = inputFactory.createXMLEventReader(xmlReader);
StAXSource source = new StAXSource(eventReader);
DOMResult result = new DOMResult();

transformer.transform(source, result);

Node document = result.getNode();

В этом случае результирующий DOM будет содержать узлы org.w3c.dom.EntityReference, смешанные с текстовыми узлами. Затем вы можете обработать их так, как считаете нужным.

2 голосов
/ 13 марта 2010

Поскольку ваш XML-ввод кажется доступным в виде строки, не могли бы вы выполнить простую предварительную обработку с заменой регулярного выражения?

xml = "...";

/* replace entities before parsing */
for (Map.Entry<String,String> entry : entityMapping.entrySet()) {
   xml = xml.replaceAll("&" + entry.getKey() + ";", entry.getValue());
}

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
...

Это довольно странно, и вы можете потратить дополнительные усилия, чтобы убедиться, что регулярные выражения совпадают только там, где они действительно должны (подумайте <entity name="&don't-match-me;"/>), но, по крайней мере, это что-то ...

Конечно, есть более эффективные способы достижения того же эффекта, чем много раз звонить replaceAll().

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

Вы можете добавить объекты в начале файла. Посмотрите здесь для получения дополнительной информации.

Вы также можете взглянуть на этот поток , где, кажется, кто-то реализовал интерфейс EntityResolver (вы также можете реализовать EntityResolver2!), Где вы можете обрабатывать объекты на лету (например, с помощью предложенной вами карты. ).

ВНИМАНИЕ: в jdk6 есть ошибка! , но вы можете попробовать ее с jdk5

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...