Я ищу лучший метод для анализа различных XML-документов с помощью приложения Java. В настоящее время я делаю это с помощью SAX и пользовательского обработчика контента, и он отлично работает - быстро и стабильно.
Я решил изучить возможность использования той же программы, которая в настоящее время получает XML-документ одного формата, получает два дополнительных формата XML-документов с различными изменениями XML-элементов. Я надеялся просто заменить ContentHandler подходящим, основанным на первом "startElement" в документе ... но, да, ContentHandler установлен и тогда документ анализируется!
... constructor ...
{
SAXParserFactory spf = SAXParserFactory.newInstance();
try {
SAXParser sp = spf.newSAXParser();
parser = sp.getXMLReader();
parser.setErrorHandler(new MyErrorHandler());
} catch (Exception e) {}
... parse StringBuffer ...
try {
parser.setContentHandler(pP);
parser.parse(new InputSource(new StringReader(xml.toString())));
return true;
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
...
Так что, похоже, я не могу сделать это так, как я изначально думал.
При этом я совершенно неправильно смотрю на это? Как лучше всего анализировать несколько отдельных XML-документов с помощью одного и того же кода обработки XML? Я пытался спросить в более общем посте ранее ... но, думаю, я был слишком расплывчатым. Из соображений скорости и эффективности я никогда особо не смотрел на DOM, потому что эти XML-документы довольно большие, и система получает около 1200 каждые несколько минут. Это просто односторонняя отправка информации
Сделать этот вопрос слишком длинным и усугубить мою путаницу; Ниже приведен макет некоторых различных XML-документов, которые я хотел бы иметь один SAX, StAX или ?? парсер чисто разобрался.
products.xml:
<products>
<product>
<id>1</id>
<name>Foo</name>
<product>
<id>2</id>
<name>bar</name>
</product>
</products>
store.xml:
<stores>
<store>
<id>1</id>
<name>S1A</name>
<location>CA</location>
</store>
<store>
<id>2</id>
<name>A1S</name>
<location>NY</location>
</store>
</stores>
manager.xml:
<managers>
<manager>
<id>1</id>
<name>Fen</name>
<store>1</store>
</manager>
<manager>
<id>2</id>
<name>Diz</name>
<store>2</store>
</manager>
</managers>




JAXB. Архитектура Java для привязки XML. В основном вы создаете xsd, определяющий ваш XML-макет (я считаю, что вы также можете использовать DTD). Затем вы передаете XSD компилятору JAXB, и компилятор создает классы Java для маршалинга и демаршалинга вашего XML-документа в объекты Java. Это действительно просто.
Кстати, есть параметры командной строки для jaxb, чтобы указать имя пакета, в который вы хотите поместить результирующие классы и т. д.
Я согласен с тем, что DTD - большой отказ, но имейте в виду, что JAXB также может связывать поддеревья с учетом Stax XMLStreamReader; кроме того, объекты Java POJO намного легче в памяти и обычно занимают гораздо меньше места, чем необработанный XML (или DOM, который в 3–5 раз больше, чем занимает сам XML!). Таким образом, использование JAXB с аннотированными POJO вполне разумно.
Вы хорошо объяснили, что хотите делать, но не объяснили почему. Существует несколько структур XML, которые упрощают маршалинг и демаршалинг объектов Java в / из XML.
Самый простой - это Commons Digester, который я обычно использую для анализа файлов конфигурации. Но если вы хотите иметь дело с объектами Java, вам следует посмотреть на Кастор, JiBX, JAXB, XMLBeans, XStream или что-то подобное. Castor или JiBX - два моих фаворита.
Я пробовал SAXParser один раз, но как только я нашел XStream, я больше не возвращался к нему. С помощью XStream вы можете создавать объекты Java и преобразовывать их в XML. Отправьте их и используйте XStream для воссоздания объекта. Очень простой в использовании, быстрый и чистый XML.
В любом случае вы должны знать, какие данные вы собираетесь получать из файла XML. Вы можете отправить их по-разному, чтобы узнать, какой парсер использовать. Или иметь объект данных, который может содержать все, но заполнена только одна структура (продукт / магазин / менеджеры). Может быть что-то вроде:
public class DataStructure {
List<ProductStructure> products;
List<StoreStructure> stors;
List<ManagerStructure> managers;
...
public int getProductCount() {
return products.lenght();
}
...
}
А с XStream convert to XML отправьте, а затем воссоздайте объект. Тогда делайте с ним что хотите.
Насколько я понимаю, проблема в том, что вы не знаете, в каком формате документ до разбора. Вы можете использовать шаблон делегата. Я предполагаю, что вы не проверяете DTD / XSD / etcetera и что для DefaultHandler нормально иметь состояние.
public class DelegatingHandler extends DefaultHandler {
private Map<String, DefaultHandler> saxHandlers;
private DefaultHandler delegate = null;
public DelegatingHandler(Map<String, DefaultHandler> delegates) {
saxHandlers = delegates;
}
@Override
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
if (delegate == null) {
delegate = saxHandlers.get(name);
}
delegate.startElement(uri, localName, name, attributes);
}
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
delegate.endElement(uri, localName, name);
}
//etcetera...
См. Документацию для XMLReader.setContentHandler (), в ней говорится:
Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin using the new handler immediately.
Таким образом, вы должны иметь возможность создать SelectorContentHandler, который потребляет события до первого события startElement, на основе которого изменяется ContentHandler на считывателе XML и передает событие первого начального элемента новому обработчику содержимого. Вам просто нужно передать XMLReader в SelectorContentHandler в конструкторе. Если вам нужно, чтобы события все передавались обработчику содержимого, зависящему от словаря, SelectorContentHandler должен кэшировать события, а затем передавать их, но в большинстве случаев в этом нет необходимости.
Кстати, в последнее время я использовал XOM почти во всех своих проектах для обработки XML, и до сих пор производительность не была проблемой.
Если вам нужна более динамичная обработка, подход Stax, вероятно, подойдет лучше, чем Sax. Это все еще довольно низкий уровень; Если вам нужен более простой подход, мои фавориты - XStream и JAXB. Но для их сопоставления требуются довольно жесткие объекты.
Согласитесь со StaxMan, который, что интересно, хочет, чтобы вы использовали Stax. Это синтаксический анализатор на основе pull, а не push, который вы сейчас используете. Однако это потребует некоторых значительных изменений в вашем коде.
:-)
Да, у меня есть некоторая предвзятость по отношению к Стаксу. Но, как я уже сказал, часто связывание данных удобнее, чем решение для потоковой передачи. Но если вам нужна потоковая передача и не требуется конвейерная обработка (нескольких этапов фильтрации), Stax проще, чем SAX.
Еще одна вещь: насколько хорош XOM (по сравнению с альтернативами), часто модель дерева не подходит, если вы не имеете дело с «ориентированным на документы» xml (~ = xhtml страницы, docbook, открытые офисные документы). Для обмена данными, конфигурационных файлов и т. д. Связывание данных удобнее, эффективнее, естественнее. Просто скажите нет древовидным моделям, таким как DOM, для этих случаев использования. Итак, JAXB, XStream, JibX хороши. Или, для большего вкуса, варочный, касторовый, xmlbeans.
VTD-XML известен как лучшая технология обработки XML для тяжелой обработки XML. См. Ссылку ниже для доказательства
http://sdiwc.us/digitlib/journal_paper.php?paper=00000582.pdf
Плакат уже указал, что предпочитает использовать потоковый парсер, такой как SAX, из-за ожидаемых объемов (1200 каждые несколько минут). Кроме того, он не знает формат какого-либо отдельного xml до тех пор, пока не начнет синтаксический анализ, поэтому решение на основе DTD недействительно!