Java Sax для анализа сложного большого файла XML - PullRequest
1 голос
/ 24 октября 2011

Я использую SAX для анализа некоторых больших XML-файлов и хочу спросить следующее: XML-файлы имеют сложную структуру. Примерно так:

<library>
    <books>
    <book>
        <title></title>
    <img>
        <name></name>
        <url></url>
    </img>
    ...
    ...
    </book>
    ...
    ...
</books>
<categories>
    <category id="abcd">
        <locations>
        <location>...</location>
    </locations>
    <url>...</url>
    </category>
    ...
    ... 
</categories>
<name>...</name>
<url>...</url>
</library>

Дело в том, что каждый из этих файлов занимает более 50 МБ, и многие теги повторяются в разных контекстах, например, URL-адрес в / books / book / img, но также в / library и в / library / Categories / category и т. д.

Мой синтаксический анализатор SAX использует подкласс DefaultHandler, в котором я переопределяю методы startElement и endElement (среди прочих). Но проблема в том, что эти методы огромны с точки зрения строк кода из-за бизнес-логики этих файлов XML. Я использую много

if ("url".equalsIgnoreCase(qName)) {
    // peek at stack and if book is on top
    // ...
    // else if category is on top
    // ...
} else if (....) {
}

Мне было интересно, есть ли более правильный / правильный / элегантный способ выполнения разбора xml.

Спасибо всем

Ответы [ 5 ]

1 голос
/ 24 октября 2011

То, что вы можете сделать, это реализовать отдельный ContentHandler для различных контекстов.Например, напишите один для <books>, один для <categories> и один для верхнего уровня.

Затем, как только вызывается метод books startElement, вы немедленно переключаете ContentHandlerиспользуя XMLReader.setContentHandler().Затем <books> определенный ContentHandler переключается обратно на обработчик верхнего уровня, когда его endElement метод вызывается для books.

Таким образом, каждый ContentHandler может сосредоточиться на своей конкретной частиXML и не нужно знать обо всех других частях.

Единственная уродливая часть - то, что определенным обработчикам нужно знать обработчик верхнего уровня и когда переключаться на него, что может быть сработановокруг, предоставляя простой «стек обработчиков», который обрабатывает это для вас.

0 голосов
/ 03 ноября 2011
0 голосов
/ 24 октября 2011

Вы можете реорганизовать обработку содержимого SAX, чтобы зарегистрировать набор правил, каждое из которых имеет свой тест, чтобы проверить, соответствует ли он элементу, и действие, которое выполняется, если это так. Это приближается к модели обработки XSLT, в то же время выполняя потоковую обработку. Или вы можете перейти на XSLT - обработка входных файлов размером 50 МБ вполне соответствует возможностям современного XSLT-процессора.

0 голосов
/ 24 октября 2011

Согласившись с мнением о том, что экспорт объекта в XML является нарушением инкапсуляции, фактическая технология, используемая для обработки тегов, которые вложены с различной длиной, не очень сложна при использовании SAX.

По сути, сохранитьStringBuffer, который будет поддерживать ваше «местоположение» в документе, который будет каталогом, похожим на представление вложенного тега, в котором вы находитесь в данный момент.Например, если на данный момент содержимое строкового буфера равно /library/book/img/url, то вы знаете, что это URL-адрес изображения в книге, а не URL-адрес какой-либо категории.

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

if ("url".equalsIgnoreCase(qName)) {
   ...
}

теперь вы можете заменить

if (location.equalsIgnoreCase("/library/book/img/url")) {
   ...
}

Если по какой-то причине вам это не нравится, есть и другие решения.Например, вы можете создать обработчик SAX, который реализует стек обработчиков, где верхний обработчик отвечает за обработку только своей части XML-документа, и он извлекает себя из стека, как только это будет сделано.Используя такую ​​схему, каждый объект создается своим собственным уникальным индивидуальным обработчиком, и некоторые обработчики в основном проверяют и направляют, какие обработчики «создания объекта» помещаются в стек обработки в соответствующее время.

Я имеюиспользовал обе техники.В обоих есть свои сильные стороны, и какой из них лучше всего зависит от ввода и необходимых объектов.

0 голосов
/ 24 октября 2011

Не уверен, спрашиваете ли вы: 1) есть ли что-то еще, что вы можете сделать, кроме проверки тега на связку строк или 2) если есть альтернатива длинному утверждению типа if-then-else.

Ответ на 1 не тот, который я нашел. Кто-то другой может заняться этим.

Ответ на 2 зависит от вашего домена. Один из способов, который я вижу, заключается в том, что если целью этого является гидратация множества объектов из файла XML, то вы можете использовать фабричный метод.

Таким образом, у первого метода фабрики есть оператор long if then else, который просто передает XML соответствующим классам. Тогда у каждого из ваших классов есть метод, подобный constructYourselfFromXmlString. Это улучшит ваш дизайн, потому что только сами объекты знают о личных данных в XML для их гидратации.

Причина, по которой это сложно, заключается в том, что если вы думаете об этом, экспорт объекта в XML и импорт обратно действительно нарушает инкапсуляцию. Ничего не поделаешь, просто есть. По крайней мере, это делает вещи немного более инкапсулированными.

НТН

...