【问题标题】:parsing XPath expression understanding EBNF production rules解析 XPath 表达式 理解 EBNF 产生规则
【发布时间】:2014-01-17 10:33:24
【问题描述】:

我有一个关于 XPath 表达式的 W3C 规范(EBNF 表示法)的初学者问题。可以在以下位置找到规范:http://www.w3.org/TR/xpath/。特别是我有一个关于理解以下表达式的问题:

(//attribute::name | //attribute::id)[starts-with(string(self::node()), "be") or starts-with(string(self::node()), "1")]

这似乎是一个有效的表达式。我使用http://www.freeformatter.com/xpath-tester.html 验证了以下 XML 文档:

<documentRoot>
<!-- Test data -->
<?xc value="2" ?>
<parent name="data" >
   <child id="1"  name="alpha" >Some Text</child>
   <child id="2"  name="beta" >
      <grandchild id="2.1"  name="beta-alpha" ></grandchild>
      <grandchild id="2.2"  name="beta-beta" ></grandchild>
   </child>
   <pet name="tigger"  type="cat" >
      <data>
         <birthday month="sept"  day="19" ></birthday>
         <food name="Acme Cat Food" ></food>
      </data>
   </pet>
   <pet name="Fido"  type="dog" >
      <description>
         Large dog!
      </description>
      <data>
         <birthday month="feb"  day="3" ></birthday>
         <food name="Acme Dog Food" ></food>
      </data>
   </pet>
   <rogue name="is this real?" >
      <data>
         Hates dogs!
      </data>
   </rogue>
   <child id="3"  name="gamma"  mark="yes" >
      <!-- A comment -->
      <description>
         Likes all animals - especially dogs!
      </description>
      <grandchild id="3.1"  name="gamma-alpha" >
         <![CDATA[ Some non-parsable character data ]]>
      </grandchild>
      <grandchild id="3.2"  name="gamma-beta" ></grandchild>
   </child>
</parent>
</documentRoot>

这给了我以下结果:

Attribute='id="1"'
Attribute='name="beta"'
Attribute='name="beta-alpha"'
Attribute='name="beta-beta"'

我不清楚哪个 EBNF 产生序列会产生上述查询。

感谢您的帮助。

【问题讨论】:

    标签: xml parsing xpath w3c ebnf


    【解决方案1】:

    分解:

    ( # 团体 //attribute::name # //@name 的长格式 | # 联合 //attribute::id # //@id 的长格式 ) # 分组结束 [ # 谓词(想想“哪里”) starts-with( # 返回真或假 string(# 返回一个字符串 self::node() # "." 的长格式 ), # ) "be" # 一个字符串字面量 ) # ) 或 # 逻辑运算符 开始于(# ...同上 细绳( # self::node() # ), # "1" # ) # ] # 结束谓词

    所以这个表达式是一个相当不必要的冗长版本

    (//@name | //@id)[starts-with(., "be") or starts-with(., "1")]
    

    选择所有名为 "name" 或 "id" 且其值以 "be" 或 "1" 开头的属性

    我不确定您为什么要为此使用 EBNF 产品(我想是家庭作业),但理解表达式本身可能会对您有所帮助。

    一些额外的说明:

    • attribute:: 指定属性轴。
    • 轴可以位于任何node test 之前(默认轴始终为child::)。
    • self:: 轴很特殊,它只包含有问题的节点。 self::node() 的缩写形式是点 (.)。这意味着如果有问题的节点是&lt;foo&gt; 节点,self::foo 会匹配它,而self::bar 不会。
    • // 是 /descendant-or-self::node()/ 的简写
    • string() 函数是多余的,因为starts-with() 无论如何都会将其参数隐式转换为字符串。
    • 联合运算符连接两个节点集。出现在两个集合中的节点不会在结果中重复。
    • 谓词应用于节点集中的每个节点,有效地过滤它。

    【讨论】:

    • To be pedantic // 是 /descendant-or-self::node()/ 的简写,而不是 /descendant::(确实,在许多情况下区别并不重要,但在某些情况下它很重要,例如使//@foo 定义明确,或者//*[1] 和/descendant::*[1] 之间的区别)
    • @Ian 谢谢,会纠正这个! — 为了更加迂腐,// 是/descendant-or-self:: 的简写——不多也不少。 node() 不是它的一部分。 :)
    • 不,// 精确地表示 /descendant-or-self::node()/,包括前导和尾随斜杠 (XPath spec §2.5)。否则,您将无法说出 //@foo 之类的内容,因为那将是 /descendant::attribute::foo(您不能在同一位置步骤中使用两个轴)。
    • 嗯。显然,直到现在我的逻辑都存在错误(这些年来!!*嚎叫*)。你是绝对正确的,感谢您向我指出这一点。
    【解决方案2】:

    我不知道如何正确表示这一点,但Expr &gt;&gt;&gt; FilterExpr Predicate:

    Expr > OrExpr > AndExpr > EqualityExpr > RelationalExpr > AdditiveExpr > MultiplicativeExpr > UnaryExpr > UnionExpr > PathExpr > FilterExpr > FilterExpr Predicate
    

    给你两部分:

    • 过滤器(//attribute::name | //attribute::id)
    • 和谓词[starts-with(string(self::node()), "be") or starts-with(string(self::node()), "1")]

    (//attribute::name | //attribute::id)

    FilterExpr > PrimaryExpr > '(' Expr ')'
    Expr > OrExpr > AndExpr > EqualityExpr > RelationalExpr > AdditiveExpr > MultiplicativeExpr > UnaryExpr > UnionExpr > UnionExpr '|' PathExpr
    

    给你//attribute::name和//attribute::id

    //attribute::name 和 //attribute::id

    PathExpr > LocationPath > AbsoluteLocationPath > AbbreviatedAbsoluteLocationPath > '//' RelativeLocationPath
    RelativeLocationPath > Step > AxisSpecifier NodeTest Predicate*
        - AxisSpecifier > AxisName '::'
            - AxisName > 'attribute'
        - NodeTest > NameTest
    

    NameTest 是 name 和 id

    谓词[starts-with(string(self::node()), "be") or starts-with(string(self::node()), "1")]

    Predicate > '[' PredicateExpr ']' > Expr > OrExpr > OrExpr 'or' AndExpr
        - OrExpr > AndExpr
        - AndExpr > EqualityExpr > RelationalExpr > AdditiveExpr > MultiplicativeExpr > UnaryExpr > UnionExpr > PathExpr > FilterExpr > PrimaryExpr > FunctionCall > FunctionName '(' ( Argument ( ',' Argument )* )? ')'
            Argument > Expr
    

    FunctionName 是 starts-with,第一个参数是另一个 FunctionCall(string 函数),第二个参数是 Literals(通过 PathExpr &gt; FilterExpr &gt; PrimaryExpr),“be”和“1”。

    最后,self::node()来自:

    RelativeLocationPath > Step > AxisSpecifier NodeTest Predicate*
        - AxisSpecifier > AxisName '::'
            - AxisName > 'attribute'
        - NodeTest > NodeType '(' ')'
    

    NodeType 是“节点”

    【讨论】:

    • 太棒了!现在我懂了。非常感谢。我完全错过了 FilterExpression 规则。我被“Step = AxisSpecifier NodeTest Predicate”困住了。非常快速和良好的回复!
    猜你喜欢
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    相关资源
    最近更新 更多