Я всегда считал, что 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 всегда превращаться в огромный конечный автомат?
источник
Ответы:
Для меня вопрос наоборот. В какой момент XML-документ становится настолько громоздким, что вам приходится использовать SAX вместо DOM?
Я бы использовал SAX только для очень большого потока данных неопределенного размера; или если поведение, которое должен вызывать XML, действительно управляемо событиями, и, следовательно, SAX-подобным.
Пример, который вы приводите, выглядит для меня очень похожим на DOM.
РЕДАКТИРОВАТЬ: Я бы также использовал SAX для потоков, которые могут быть искажены, но там, где я хочу сделать наилучшее предположение при получении данных.
источник
Я не слишком много работаю с XML, хотя, на мой взгляд, возможно, один из лучших способов анализа XML с помощью библиотеки - это использование XPath.
Вместо того, чтобы обходить дерево, чтобы найти какой-то конкретный узел, вы указываете путь к нему. В случае вашего примера (в псевдокоде) это будет что-то вроде:
XPath намного мощнее, вы можете выполнять поиск с использованием условий (как по значениям, так и по атрибутам), выбирать определенный узел в списке, перемещать уровни по дереву. Я рекомендую вам поискать информацию о том, как его использовать, он реализован во многих библиотеках синтаксического анализа (я использую его. Версия .Net Framework и lxml для Python)
источник
Обычно так и есть, да.
Я хочу указать, что использовать полноценный парсер DOM - это когда мне нужно имитировать части файловой иерархии в памяти, например, чтобы иметь возможность разрешать перекрестные ссылки в документе.
источник
В целом, синтаксический анализ - это просто управление конечным автоматом, и синтаксический анализ XML ничем не отличается. Анализ на основе потоков - это всегда хлопотно, я всегда собираюсь создать какой-то стек для отслеживания узлов-предков и определить множество событий и некоторый тип диспетчера событий, который проверяет реестр тегов или путей и запускает событие если один соответствует. Основной код довольно труден, но я получаю огромное количество обработчиков событий, которые в основном состоят из назначения значения следующего текстового узла какому-либо полю в структуре. Это может стать довольно странным, если вам нужно смешать бизнес-логику.
Я бы всегда использовал DOM, если только размер или производительность не определялись иначе.
источник
Не полностью зависит от языка, но я обычно десериализирую XML в объекты, а не думаю о разборе. Единственное время, которое нужно беспокоиться о стратегиях синтаксического анализа как таковых, - это проблема скорости.
источник
Это станет намного менее громоздким, если вы можете использовать XPath. И в .Net land LINQ to XML также абстрагирует множество менее гламурных вещей. ( Изменить - это, конечно, требует подхода DOM)
По сути, если вы используете потоковый подход (поэтому вы не можете использовать более хорошие абстракции, требующие DOM), я думаю, что это всегда будет довольно громоздким, и я не уверен, что есть какой-то способ обойти это.
источник
Если вы можете найти парсер, который дает вам итератор, задумывались ли вы о том, чтобы рассматривать его как лексер и использовать генератор конечных автоматов?
источник