如何从头创建/编写一个简单的XML解析器?

XP1*_*XP1 22 xml d xml-parsing

如何从头创建/编写一个简单的XML解析器?

我想知道英语中简化的基本步骤,而不是代码示例.

一个好的解析器是如何设计的?我知道正则表达式不应该在解析器中使用,但正则表达式在解析XML中的作用是多少?

建议的数据结构是什么?我应该使用链表来存储和检索节点,属性和值吗?

我想学习如何创建XML解析器,以便我可以用D编程语言编写一个.

Mic*_*Kay 11

如果您不知道如何编写解析器,那么您需要进行一些阅读.掌握任何关于编译器编写的书(许多最好的书是在30或40年前编写的,例如Aho和Ullmann)并研究词汇分析和语法分析的章节.XML基本上没有什么不同,除了词法和语法阶段不像某些语言那样彼此明显隔离.

一句警告,如果你想编写一个完全符合要求的XML解析器,那么90%的努力将用于在规范的模糊角落中处理边缘情况,例如大多数XML用户甚至不参与的参数实体意识到.

  • 好奇,什么数据结构最适合这项任务?我的直觉告诉我,这是一棵通用树,并且不知道 OP 是否也想从头开始构建它,他/她可能会参与一个漫长的项目。 (2认同)

Gol*_*rol 6

解析器和节点列表之间存在差异.解析器是一个部分,它接受一堆纯文本XML并尝试确定那里有哪些节点.然后是一个保存节点的内部结构.在该结构的一个层中,您可以找到DOM,即文档对象模型.这是构成XML文档的嵌套节点的结构.解析器只需知道通用DOM接口即可创建节点.

我不会使用正则表达式作为解析器.我认为最好的事情只是通过char遍历字符串char并检查你得到的是否与你应该得到的匹配.

但为什么不使用任何现有的XML解析器呢?编码数据有很多种可能性.很多例外.如果您的解析器不管理它们,则几乎不值得使用XML解析器的标题.


rat*_*eak 5

并基于事件的解析器,用户需要通过它的一些功能(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's 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在基于事件的解析器之上构建DOM解析器,并且每个节点所需的基本功能是getChildren和getParent getName和getAttributes(在构建时使用setter;))

使用上述方法的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));
    }
}
Run Code Online (Sandbox Code Playgroud)

当解析结束时,rootnode将具有DOM树的根

注意:我没有在其中放置任何验证码以确保xml的正确性

编辑:属性的解析有一个错误,而不是在空格上拆分正则表达式更好