Я всегда считал, что XML довольно сложно обрабатывать. Я не говорю о реализации парсера XML: я говорю об использовании существующего потокового парсера, такого как парсер SAX, который обрабатывает XML узел за узлом.
Да, действительно легко изучить различные API для этих синтаксических анализаторов, но всякий раз, когда я смотрю на код, обрабатывающий XML, я всегда нахожу его несколько запутанным. Кажется, что существенная проблема заключается в том, что документ XML логически разделен на отдельные узлы, и все же типы данных и атрибуты часто отделены от фактических данных, иногда несколькими уровнями вложенности. Поэтому при индивидуальной обработке любого конкретного узла необходимо поддерживать много дополнительных состояний, чтобы определить, где мы находимся и что нам нужно делать дальше.
Например, учитывая фрагмент из типичного XML-документа:
<book>
<title>Blah blah</title>
<author>Blah blah</author>
<price>15 USD</price>
</book>
... Как определить, когда я столкнулся с текстовым узлом, содержащим название книги? Предположим, у нас есть простой анализатор XML, который действует как итератор, давая нам следующий узел в документе XML каждый раз, когда мы вызываем XMLParser.getNextNode()
. Я неизбежно обнаруживаю, что пишу такой код:
boolean insideBookNode = false;
boolean insideTitleNode = false;
while (!XMLParser.finished())
{
....
XMLNode n = XMLParser.getNextNode();
if (n.type() == XMLTextNode)
{
if (insideBookNode && insideTitleNode)
{
// We have a book title, so do something with it
}
}
else
{
if (n.type() == XMLStartTag)
{
if (n.name().equals("book")) insideBookNode = true
else if (n.name().equals("title")) insideTitleNode = true;
}
else if (n.type() == XMLEndTag)
{
if (n.name().equals("book")) insideBookNode = false;
else if (n.name().equals("title")) insideTitleNode = false;
}
}
}
По сути, обработка XML быстро превращается в огромный цикл, управляемый конечным автоматом, с большим количеством переменных состояния, используемых для обозначения родительских узлов, которые мы нашли ранее. В противном случае необходимо сохранить объект стека для отслеживания всех вложенных тегов. Это быстро становится подверженным ошибкам и трудным в обслуживании.
Опять же, проблема заключается в том, что интересующие нас данные не связаны напрямую с отдельным узлом. Конечно, это может быть, если мы напишем XML как:
<book title="Blah blah" author="blah blah" price="15 USD" />
... но это редко, как XML используется в реальности. В основном у нас есть текстовые узлы как дочерние узлы родительских узлов, и нам нужно отслеживать родительские узлы, чтобы определить, к чему относится текстовый узел.
Итак ... я делаю что-то не так? Есть ли способ лучше? В какой момент использование парсера на основе XML-потока становится слишком громоздким, так что становится необходимым полноценный парсер DOM? Я хотел бы услышать от других программистов, какие идиомы они используют при обработке XML с помощью потоковых парсеров. Должен ли потоковый анализ XML всегда превращаться в огромный конечный автомат?