Pull to refresh

Comments 17

Если правильно понимаю, то то, что является "потоковым" Xml.Reader работает по принципу XML-SAX. А есть ли в нем автоматическая обработка сложных структур, когда один и тот же тег может находиться внутри разных тегов. Например:

        <ТипСубъекта>
          <Идентификатор>2</Идентификатор>
          <Наименование>Физическое лицо</Наименование>
        </ТипСубъекта>

        <ТипДокумента>
           <Идентификатор>746140005</Идентификатор>
           <Наименование>PASSPORT</Наименование>
        </ТипДокумента>

Т.е. теги Идентификатор и Наименование являются универсальными и относятся к тому тегу, внутри которого находятся (ТипСубъекта или ТипДокумента), являясь контекстно-зависимыми.

Есть возможность такие вещи автоматически распознавать (т.е. не reader.Name == "Идентификатор", но reader.Name == "ТипДокумента.Идентификатор"), или надо руками отслеживать внутри какого тега сейчас находимся?

Блин, да посмотрите вы на код из статьи внимательнее! Никакой это не SAX, это, ну, Reader.

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

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

Есть возможность такие вещи автоматически распознавать (т.е. не reader.Name == "Идентификатор", но reader.Name == "ТипДокумента.Идентификатор"), или надо руками отслеживать внутри какого тега сейчас находимся?

Второе, потому что reader.Name - это имя тэга и ничего кроме имени тэга. Однако, если использовать валидацию по схеме, то можно получить ссылку на текущий элемент и его тип в схеме.

Блин, да посмотрите вы на код из статьи внимательнее! Никакой это не SAX, это, ну, Reader.

SAX (англ. «Simple API for XML») — способ последовательного чтения/записи XML-файлов.

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

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

Это действительно удобно когда нужно просто извлечь из XML какие-то данные и потом с ними что-то делать.

Работал с таким (причем, XML были достаточно объемные - несколько десятков Мб). Правда, в той реализации, что у меня была под рукой, задавался callback handler, вызываемый "изнутри" с параметрами "код события" + "данные". Коды собятия там были типа "начало тега" (с именем тега в данных), "содержимое тега", "конец тега" и т.п. И да, для описанной выше ситуации приходилось выставлять флаги "внутри тега ТипСубъекта" или "внутри тега ТипДокумента" чтобы правильно обрабатывать теги Идентификатор и ТипДокумента.

Спросил потому что думал вдруг придумали что-то более умное, типа "полного имени тега" (какое-нибудь свойство fullname) для вложенных тегов.

SAX (англ. «Simple API for XML») — способ последовательного чтения/записи XML-файлов

Это не любой способ, а конкретный способ с конкретным подходом к построению API. XmlReader не реализует этот подход.

Работал с таким (причем, XML были достаточно объемные - несколько десятков Мб). Правда, в той реализации, что у меня была под рукой, задавался callback handler, вызываемый "изнутри" с параметрами "код события" + "данные"

Этот способ и называется SAX...

Спросил потому что думал вдруг придумали что-то более умное, типа "полного имени тега" (какое-нибудь свойство fullname) для вложенных тегов.

Ну, кое-что придумано, только в другом направлении. В отличии от SAX, XmlReader не требует единого места обработки абсолютно всех элементов. Никто не мешает делать вложенные циклы, и вообще структурировать программу по всем правилам структурного программирования:

Примерный код:

if (reader.Name == "ТипСубъекта") ReadSubject(reader);

// ...

void ReadSubject(XmlReader reader)
{
    while(reader.Read())
    {
        if (reader.NodeType == XmlNodeType.Element && reader.Name == "Идентификатор")
            subjectTypeId = reader.ReadElementContentAsString();

        else if (reader.NodeType == XmlNodeType.Element && reader.Name == "Наименование")
            subjectTypeName = reader.ReadElementContentAsString();

        else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "ТипСубъекта")
            return;
    }
    throw ...;
}

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

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

Подобный подход тоже использовал.

Но в SAX все равно передается что-то одно - обработчик верхнего уровня. Ну а дальше он уже должен решать по текущему состоянию - куда отдавать дальнейшую обработку элемента. Т.е. там все равно какие-то флаги нужны.

В моем понимании SAX - это общий принцип. Не построение всего дерева документа в памяти (как в DOM), а потоковое чтение и действия на каждый прочитанный элемент. В том SAX с которым я работал те циклы, что указаны в reader просто спрятаны внутрь. Не берусь судить что удобнее - надо пробовать под конкретную задачу.

А для простейших одноуровневых XML типа

<Person>
    <Name>Ivan</Name>
    <Age>30</Age>
</Person>

В используемом мной языке вообще есть XML-INTO - там просто создаешь структуру с именами полей, совпадающими с именами тегов, дергаешь XML-INTO и сразу получаешь заполненную структуру.
Минус - с русскими тегами не работает :-(

В моем понимании SAX - это общий принцип. Не построение всего дерева документа в памяти (как в DOM), а потоковое чтение и действия на каждый прочитанный элемент.

Потоковое чтение называется "потоковое чтение", ему не требуется специальное название.

В том SAX с которым я работал те циклы, что указаны в reader просто спрятаны внутрь.

То-то и оно, что они не "просто спрятаны", а фундаментально спрятаны. Архитектура SAX и XmlReader принципиально различаются, как и способы их использования, возникающие при этом проблемы и способы их решения.

В используемом мной языке вообще есть XML-INTO - там просто создаешь структуру с именами полей, совпадающими с именами тегов, дергаешь XML-INTO и сразу получаешь заполненную структуру. Минус - с русскими тегами не работает :-(

Это называется "десериализация", в C# ей занимается XmlSerializer. С русскими тэгами без проблем работает. Можно комбинировать с потоковым чтением при необходимости (верхний уровень читается потоково, а нижний десериализуется).

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

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

Впрочем, это все вопрос терминологии.

Если походить по страницам по вашей ссылке, то можно найти и такое: "Росси́я, или Росси́йская Федера́ция (сокр. РФ), — государство в Восточной Европе и Северной Азии.". Означает ли это, что любое государство в Восточной Европе - это Россия?

SAX - это имя собственное, и оно означает один конкретный набор интерфейсов в Java и ничего более.

К слову, гляньте один из источников по вашей же ссылке: http://www.saxproject.org/

Есть возможность такие вещи автоматически распознавать (т.е. не reader.Name == "Идентификатор", но reader.Name == "ТипДокумента.Идентификатор")

тогда вам не ридер нужен, а язык запросов, например XPath (XML Path Language) 

Ридер просто загружает XML из файла в память, есть два основных способа, загрузить и отдать пользователю полностью дерево XML объектов (узлов, элементов, ... как хотите называйте)

или отдавать XML объекты по мере чтения.

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

Через XPath можно запросить, то есть найти, все узлы которые имеют Идентификатор как дочерний узел, можно найти все узлы путь к которым заканчивается на "ТипДокумента.Идентификатор"

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

Не совсем так. Мне вполне хватило чтобы ридер знал "полное имя тега". Т.е. для указанного выше случая (как уже написал выше) можно было смотреть как свойство name - например, "Идентификатор", так и свойство fullname (или qualifiedname - как угодно), например, "ТипДокумента.Идентификатор". Ну или свойство path - "ТипДокумента"

С точки зрения реализации это не является чем-то невозможным - ридер идет по документу последовательно и вполне способен "накапливать" последовательность имен тегов, внутри которой находится в текущий момент.

И да, все это легко реализуется руками, но было бы чуть удобнее, если бы оно уже было "из коробки". Но раз нет - говорить не о чем.

И да, все это легко реализуется руками, но было бы чуть удобнее, если бы оно уже было "из коробки". Но раз нет - говорить не о чем.

XML парсер существует (даже с С++ интерфейсом) и успешно (хотя не всегда конечно) используется уже более 20 лет, и интерфейс к нему существует столько же. Вы считаете что за 20 лет никто бы не догадался сделать что-то лучше, если оно действительно лучше?

Потом что значит "чуть удобнее"? Так можно дойти до того, что было бы даже намного удобнее если бы всю работу уже кто-то сделал за вас, только возникает тогда вопрос, а вы то зачем тогда нужны как технический специалист, коробки переставлять? Никогда не понимал такого отношения!

XPath это уже про DOM модель парсера. На паре гигибайт данных это такое себе удовольствие.

SAX парсер безальтернативен на больших данных, и да, там придется флажки ставить "нода открылась, нода закрылась".

XmlReader - вполне себе альтернатива SAX парсеру. Но да, XPath он тоже не умеет.

Кстати, на Java тот же Saxon умудряется ограниченно комбинировать XPath и потоковый разбор, однако я не вижу способа дёшево "достать" из него этот механизм.

Фактически - тот же SAX, просто в другой реализации.

Два подхода - DOM с построением всего дерева в памяти и SAX потоковым чтением. Как все это реализовать к конкретике - тут уже возможны варианты.

Именно так, это просто SAX с красивой оберткой. Полноценный XPath возможен только после полного построения дерева элементов. А это однозначно DOM парсер.

И еще комментарий: использовать DOM без четкого понимания (контракта с внешней системой) объемов данных - это стрелять себе в ноги крупной дробью. SAX при первоначальной бОльшей трудности реализации, делает систему гораздо более устойчивой и прогнозируемой. Надо только способ получения потока данных реализовывать не полным чтением в память.

По-моему, тема не раскрыта. В чём разница между XmlDocument и XDocument, между XmlReader и SAX-парсерами и т.п.

Когда на основании xml делаются некие небольшие конфиги, это еще ладно, но когда конфиг в одном файле составляет 166 страниц, то работа с ним превращается в кошмар. В одной такой задаче пришлось переносить 40 файлов из xml в базу данных и заново писать приложение и это тот еще был квест. Распарсить xml в таблицу БД несложно, но там получается такое дерево, что надо очень сильно постараться это все обработать правильно, не теряя связи. У меня были еще относительно простые варианты xml, где надо было разложить в 5 таблиц не потеряв связи между таблицами. В общем очень нетривиальная задача для SQL.

Sign up to leave a comment.