Подтвердить что ты не робот

Как создать/написать простой парсер XML с нуля?

Как создать/написать простой парсер XML с нуля?

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

Как работает хороший парсер? Я понимаю, что регулярное выражение не должно использоваться в синтаксическом анализаторе, но насколько важна роль регулярных выражений при анализе XML?

Какова рекомендуемая структура данных? Должен ли я использовать связанные списки для хранения и извлечения узлов, атрибутов и значений?

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

4b9b3361

Ответ 1

Если вы не знаете, как писать синтаксический анализатор, вам нужно сделать некоторое чтение. Возьмите любую книгу по написанию компилятора (многие из лучших были написаны 30 или 40 лет назад, например, Ахо и Ульманн) и изучили главы по лексическому анализу и синтаксическому анализу. XML по существу не отличается, за исключением того, что лексические и грамматические фазы не так четко изолированы друг от друга, как на некоторых языках.

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

Ответ 2

Существует разница между парсером и ноделистом. Парсер - это кусок, который берет кучу простого текстового XML и пытается определить, какие узлы там находятся. Затем есть внутренняя структура, в которой вы сохраняете узлы. В слое над этой структурой вы найдете DOM - объектную модель документа. Это структура вложенных узлов, которые составляют ваш XML-документ. Анализатор должен знать только общий интерфейс DOM для создания узлов.

Я бы не использовал regex как синтаксический анализатор для этого. Я думаю, что лучше всего просто пересечь строку char на char и проверить, соответствует ли то, что вы получаете, с тем, что вы должны получить.

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

Ответ 3

для анализатора, основанного на событии, пользователю необходимо передать ему некоторые функции (startNode(name,attrs), endNode(name) и someText(txt), вероятно, через интерфейс) и вызвать их при необходимости при передаче файла

анализатор будет иметь цикл while, который будет чередоваться между чтением до < и до > и выполнять правильные преобразования типов параметров

void parse(EventParser p, File file){
    string str;
    while((str = file.readln('<')).length !=0){
        //not using a rewritable buffer to take advantage of slicing 
        //but it a quick conversion to a implementation with a rewritable buffer though
        if(str.length>1)p.someText(str.chomp('<'));


        str = file.readln('>');
        str = str.chomp('>');

        //split str in name and attrs
        auto parts = str.split();
        string name = parts[0];
        string[string] attrs;
        foreach(attribute;parts[1..$]){
            auto splitAtrr = attribute.split("=");
            attrs[splitAtrr[0]] = splitAtrr[1];
        }

        if(str[0] == '/')p.endNode(name);
        else {
            p.startNode(name,attrs);
            if(str[str.length-1]=='/')p.endNode(name);//self closing tag
        }
    }
}

вы можете создать парсер DOM поверх синтаксического анализа, основанного на событиях, и основные функции, необходимые для каждого node, - это getChildren и getParent getName и getAttributes (с сеттерами при построении;))

объект для парсера dom с описанными выше способами:

class DOMEventParser : EventParser{
    DOMNode current = new RootNode();
    overrides void startNode(string name,string[string] attrs){
        DOMNode tmp = new ElementNode(current,name,attrs);
        current.appendChild(tmp);
        current = tmp;
    }
    overrides void endNode(string name){
        asser(name == current.name);
        current = current.parent;
    }
    overrides void someText(string txt){
        current.appendChild(new TextNode(txt));
    }
}

когда синтаксический анализ заканчивается, rootnode будет иметь корень дерева DOM

note: я не добавил код проверки для обеспечения правильности xml

edit: при анализе атрибутов в нем есть ошибка, вместо того, чтобы расщепляться по пробелу, для этого лучше использовать регулярное выражение

Ответ 4

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

D обеспечивает очень интересный способ написания синтаксического анализа XML очень легко, например:

doc.onStartTag["pointlight"] = (ElementParser xml)
{
  debug writefln("Parsing pointlight element");

  auto l = new DistantLight(to!int(xml.tag.attr["x"]),
                            to!int(xml.tag.attr["y"]),
                            to!int(xml.tag.attr["z"]),
                            to!ubyte(xml.tag.attr["red"]),
                            to!ubyte(xml.tag.attr["green"]),
                            to!ubyte(xml.tag.attr["blue"]));
  lights ~= l;

  xml.parse();
};

Ответ 5

Так как D довольно тесно связан с Java, возможно, генерирует синтаксический анализатор XML с ANTLR (поскольку, скорее всего, XML EBNF для ANTLR, вы могли бы использовать их), а затем преобразование сгенерированного кода парсера Java в D может быть вариантом? По крайней мере, это даст вам отправную точку, и вы могли бы приложить некоторые усилия, пытаясь оптимизировать код специально для D...

По крайней мере, ANTLR не так сложно, как многие думают. Я начал, ничего об этом не узнав, просмотрев 3-4 из этот отличный набор скринкастов на ANTLR.

Btw, я нашел ANTLRWorks легкий ветерок для работы (в отличие от плагина Eclipse, используемого в screencast... но содержимое скринкаста применяется в любом случае).

Просто мой 0.02c.

Ответ 6

Первым элементом в документе должен быть пролог. Это указывает версию xml, кодировку, независимо от того, является ли файл автономным, и, возможно, некоторым другим. Пролог открывается с помощью <?.

После пролога есть теги с метаданными. Специальные теги, такие как комментарии, доктики и определения элементов, должны начинаться с <!. Инструкции по обработке начинаются с <?. Здесь можно иметь вложенные теги, поскольку тег <!DOCTYPE может иметь теги <!ELEMENT и <!ATTLIST в XML-документе стиля dtd - см. Wikipedia для подробного примера.

Должен быть ровно один элемент верхнего уровня. Он единственный, у которого есть <! или <?, предшествующие ему. После элемента верхнего уровня может быть больше тегов метаданных; сначала обработайте их.

Для явного синтаксического анализа: сначала идентифицируйте теги - все они начинаются с < - затем определите, какой тип тега он и как выглядит его закрытие. <!-- является тегом комментариев и не может иметь -- везде, кроме его конца. <? заканчивается на ?>. <! заканчивается на >. Повторить: <!DOCTYPE может иметь теги, вложенные до его закрытия, и могут быть другие вложенные теги, о которых я не знаю.

Как только вы найдете тег, вы захотите найти его закрывающий тег. Проверьте, закрывается ли сам тег; в противном случае найти его замыкание.

Для структур данных: я бы рекомендовал древовидную структуру, где каждый элемент является node, и каждый node имеет индексированный/отображаемый список подэлементов.

Очевидно, что полный анализатор потребует гораздо больше исследований; Надеюсь, этого достаточно, чтобы вы начали.