gpt4 book ai didi

c++ - Boost.Spirit,如何扩展xml解析?

转载 作者:行者123 更新时间:2023-11-30 04:29:19 25 4
gpt4 key购买 nike

我想使用 Boost.Spirit 扩展 xml 解析,并想添加 xml 属性的解析。

这里是图书馆的例子和我的一些修改:

template <typename Iterator>
struct mini_xml_grammar
: qi::grammar<Iterator, mini_xml(), qi::locals<std::string>, ascii::space_type>
{
mini_xml_grammar()
: mini_xml_grammar::base_type(xml, "xml")
{
using qi::lit;
using qi::lexeme;
using qi::attr;
using qi::on_error;
using qi::fail;
using ascii::char_;
using ascii::string;
using ascii::alnum;
using ascii::space;

using namespace qi::labels;

using phoenix::construct;
using phoenix::val;


text %= lexeme[+(char_ - '<')];
node %= xml | text;


start_tag %=
'<'
>> !lit('/')
> lexeme[+(char_ - '>')]
> '>'
;

end_tag =
"</"
> string(_r1)
> '>'
;

xml %=
start_tag[_a = _1]
> *node
> end_tag(_a)
;

xml.name("xml");
node.name("node");
text.name("text");
start_tag.name("start_tag");
end_tag.name("end_tag");

on_error<fail>
(
xml
, std::cout
<< val("Error! Expecting ")
<< _4 // what failed?
<< val(" here: \"")
<< construct<std::string>(_3, _2) // iterators to error-pos, end
<< val("\"")
<< std::endl
);
}

qi::rule<Iterator, mini_xml(), qi::locals<std::string>, ascii::space_type> xml;
qi::rule<Iterator, mini_xml_node(), ascii::space_type> node;
qi::rule<Iterator, std::string(), ascii::space_type> text;
qi::rule<Iterator, std::string(), ascii::space_type> attribute;
qi::rule<Iterator, std::string(), ascii::space_type> start_tag;
qi::rule<Iterator, void(std::string), ascii::space_type> end_tag;
};

我试过这个,但它没有编译错误“使用未声明的标识符‘eps’”:

        xml %= 
start_tag[_a = _1]
> attribute
> ( "/>" > eps
| ">" > *node > end_tag(_a)
)
;

有人知道怎么做吗?如何添加解析xml属性的能力?

最佳答案

eps 标识符与您使用的许多其他标识符一样,是在 qi 命名空间中定义的。其他人通过构造函数顶部的 using 语句进入全局命名空间。对 eps 做同样的事情:

using qi::eps;

一旦你解决了这个问题,你就会遇到一个更大的问题,即你是否正确地表示了 XML 的句法和语法。看起来你做对了。你有这个:

xml %= 
start_tag[_a = _1]
> attribute
> ( "/>" > eps
| ">" > *node > end_tag(_a)
)
;

不过,这不可能是对的。属性是标签的一部分,而不是标签后面的东西。看起来你想打破 start_tag appart 以便你可以处理空标签。如果我这样做,我可能会改为创建一个 empty_tag 规则,然后将 xml 更改为 empty_tag | (start_tag > *node > end_tag)。就是这样the W3C language recommendation这样做:

[39]  element   ::= EmptyElemTag
| STag content ETag

但现在不要担心。请记住,您声明的任务是向解析器添加属性。不要因其他缺失的功能而分心。以后还有很多工作要做。

我提到了 W3C 文档。你应该经常提到它;它定义了语言,甚至显示了语法。 Spirit 的设计目标之一是它应该看起来像语法定义。通过尝试在您自己的代码中模仿 W3C 语法来利用它。 W3C defines the start tag像这样:

[40]  STag      ::= '<' Name (S Attribute)* S? '>'
[41] Attribute ::= Name Eq AttValue

所以这样写你的代码:

start_tag %=
// Can't use operator> for "expect" because empty_tag
// will be the same up to the final line.
'<'
>> !lit('/')
>> name
>> *attribute
>> '>'
;

name %= ...; // see below

attribute %=
name
> '='
> attribute_value
;

规范定义了属性值语法:

[10]  AttValue  ::= '"' ([^<&"] | Reference)* '"'
| "'" ([^<&'] | Reference)* "'"

我还不担心实体引用。与空标签一样,您当前的代码已经不支持它们,因此现在将它们添加为属性的一部分并不重要。这使得 attribute_value 易于定义:

attribute_value %=
'"' > *(char_ - char_("<&\"")) > '"'
| '\'' > *(char_ - char_("<&'")) > '\''
;

name 定义不必是任何花哨的东西。它在规范中很复杂,因为它处理完整的 Unicode 字符范围,但您可以从更简单的内容开始,然后在您弄清楚如何在整个解析器中处理 Unicode 字符时再回过头来。

name %=
lexeme[char_("a-zA-Z:_") >> *char_("-a-zA-Z0-9:_")]
;

这些更改应该允许您解析 XML 属性。 但是,将结果提取为 Spirit 属性是另一回事(这样您就可以知道程序其余部分中给定标签的属性名称和值),并且我现在不准备讨论这个问题。

关于c++ - Boost.Spirit,如何扩展xml解析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9473843/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com