2014-01-17 72 views
0

我有一個關於XPath表達式的W3C規範(EBNF表示法)的初學者問題。該規範可在以下網址找到:http://www.w3.org/TR/xpath/。特別是我有一個關於理解以下表達式的問題:解析XPath表達式瞭解EBNF生產規則

(//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作品的順序會產生上面的查詢。

感謝您的幫助。

回答

1

我不知道如何正確地表現這一點,但Expr >>> FilterExpr Predicate

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

爲您提供了2個部分:

  • 過濾(//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 

NameTestnameid

謂詞[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 

FunctionNamestarts-with,第一個參數是另一個FunctionCallstring功能),第二個參數是Literal S(經由PathExpr > FilterExpr > PrimaryExpr), 「是」 和 「1」。

最後,自::節點()來源於:

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

NodeType被 '節點'

+0

太棒了!現在我懂了。非常感謝。我完全錯過了FilterExpression規則。我被卡住了「Step = AxisSpecifier NodeTest Predicate」。很快,很好的答覆! – user1362700

2

擊穿:

 
(      # group 
    //attribute::name  # the long form of //@name 
    |      # union 
    //attribute::id  # the long form of //@id 
)      # group end 
[      # predicate (think "where") 
    starts-with(   # returns true or false 
    string(    #  returns a string 
     self::node()  #  the long form of "." 
    ),     # ) 
    "be"     #  a string literal 
)      # ) 
    or      # logical operator 
    starts-with(   # ...idem 
    string(    # 
     self::node()  # 
    ),     # 
    "1"     # 
)      # 
]      # end predicate 

所以表達式是

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

相當不必要詳細的版本選擇命名"name""id"其值開始"be""1"

所有屬性我不知道你爲什麼要這個EBNF作品(家庭作業,我假設),但理解表達本身可能會幫助你。

一些額外的注意事項:

  • attribute::指定屬性
  • 軸可以在任何node test之前(默認軸始終爲child::)。
  • self::是特殊的,它只包含有問題的節點。 self::node()的簡寫形式是點(.)。其含義是,如果有問題的節點是<foo>節點,則self::foo將與其匹配,而self::bar則不會。
  • ///descendant-or-self::node()/
  • 速記的string()功能是多餘的,因爲starts-with()將其參數轉換爲字符串隱含反正。
  • 聯合運算符加入兩個節點集。出現在兩組中的節點在結果中不重複。
  • 謂詞應用於節點集中的每個節點,並對其進行有效過濾。
+1

要學究''//爲'/後代或自身的簡寫:: node()/',而不是'/ descendant ::'(true,在許多情況下,區別並不重要,但有些情況下它很重要,例如,使得// @ foo明確定義,或者'// * [1]'和'/ descendant :: * [1]'之間的區別) –

+0

@Ian謝謝! - 更迂腐的是,''/''是'/ descendant-or-self ::'的縮寫 - 毫無疑問,但僅此而已。 'node()'不是它的一部分。 :) – Tomalak

+3

不,'//'意思是'/ descendant-or-self :: node()/',包括前後斜線([XPath spec§2.5](http://www.w3.org/TR /的xpath /#路徑縮寫))。否則,你將無法像'// foo'那樣說'/ descendant :: attribute :: foo'(你不能在同一個位置步驟中使用兩個座標軸)。 –