2009-02-05 2 views
6

Я пытаюсь создать «AET» (абстрактное дерево выражений) для XPath (поскольку я пишу WYSIWYG XSL-редактор). Я бил головой о стену с помощью XPath BNF в течение последних трех-четырех часов.Parse XPath Expressions

Я подумал о другом решении. Я думал, что могу написать класс, который реализует IXPathNavigable, который возвращает собственный XPathNavigator при вызове CreateNavigator. Этот XPathNavigator всегда будет успешным при любых вызовах методов и будет отслеживать эти вызовы - например. мы перешли к узлу клиентов, а затем к узлу клиента. Затем я мог бы использовать эту информацию (надеюсь) для создания «AET» (так что у нас теперь будут клиенты/клиенты в объектной модели).

Только вопрос: как на земля ли я запускаю IXPathNavigable через XPathExpression?

Я знаю, что это слишком лениво. Но кто-нибудь еще прошел через это усилие и написал парсер выражения XPath? У меня еще нет POC'd моего возможного решения, потому что я не могу проверить его (потому что я не могу запустить XPathExpression против IXPathNavigable), поэтому я даже не знаю, будет ли мое решение работать.

+0

Текст, начинающийся с IXPathNavigable, очень запутан. Не могли бы вы изменить вопрос и объяснить лучше? –

ответ

2

Существует грамматика antlr xpath here. Поскольку лицензия разрешена, я копировал всю грамматику здесь, чтобы избежать гниения ссылок в будущем.

grammar xpath; 

/* 
XPath 1.0 grammar. Should conform to the official spec at 
http://www.w3.org/TR/1999/REC-xpath-19991116. The grammar 
rules have been kept as close as possible to those in the 
spec, but some adjustmewnts were unavoidable. These were 
mainly removing left recursion (spec seems to be based on 
LR), and to deal with the double nature of the '*' token 
(node wildcard and multiplication operator). See also 
section 3.7 in the spec. These rule changes should make 
no difference to the strings accepted by the grammar. 
Written by Jan-Willem van den Broek 
Version 1.0 
Do with this code as you will. 
*/ 
/* 
    Ported to Antlr4 by Tom Everett <[email protected]> 
*/ 


main : expr 
    ; 

locationPath 
    : relativeLocationPath 
    | absoluteLocationPathNoroot 
    ; 

absoluteLocationPathNoroot 
    : '/' relativeLocationPath 
    | '//' relativeLocationPath 
    ; 

relativeLocationPath 
    : step (('/'|'//') step)* 
    ; 

step : axisSpecifier nodeTest predicate* 
    | abbreviatedStep 
    ; 

axisSpecifier 
    : AxisName '::' 
    | '@'? 
    ; 

nodeTest: nameTest 
    | NodeType '(' ')' 
    | 'processing-instruction' '(' Literal ')' 
    ; 

predicate 
    : '[' expr ']' 
    ; 

abbreviatedStep 
    : '.' 
    | '..' 
    ; 

expr : orExpr 
    ; 

primaryExpr 
    : variableReference 
    | '(' expr ')' 
    | Literal 
    | Number 
    | functionCall 
    ; 

functionCall 
    : functionName '(' (expr (',' expr)*)? ')' 
    ; 

unionExprNoRoot 
    : pathExprNoRoot ('|' unionExprNoRoot)? 
    | '/' '|' unionExprNoRoot 
    ; 

pathExprNoRoot 
    : locationPath 
    | filterExpr (('/'|'//') relativeLocationPath)? 
    ; 

filterExpr 
    : primaryExpr predicate* 
    ; 

orExpr : andExpr ('or' andExpr)* 
    ; 

andExpr : equalityExpr ('and' equalityExpr)* 
    ; 

equalityExpr 
    : relationalExpr (('='|'!=') relationalExpr)* 
    ; 

relationalExpr 
    : additiveExpr (('<'|'>'|'<='|'>=') additiveExpr)* 
    ; 

additiveExpr 
    : multiplicativeExpr (('+'|'-') multiplicativeExpr)* 
    ; 

multiplicativeExpr 
    : unaryExprNoRoot (('*'|'div'|'mod') multiplicativeExpr)? 
    | '/' (('div'|'mod') multiplicativeExpr)? 
    ; 

unaryExprNoRoot 
    : '-'* unionExprNoRoot 
    ; 

qName : nCName (':' nCName)? 
    ; 

functionName 
    : qName // Does not match nodeType, as per spec. 
    ; 

variableReference 
    : '$' qName 
    ; 

nameTest: '*' 
    | nCName ':' '*' 
    | qName 
    ; 

nCName : NCName 
    | AxisName 
    ; 

NodeType: 'comment' 
    | 'text' 
    | 'processing-instruction' 
    | 'node' 
    ; 

Number : Digits ('.' Digits?)? 
    | '.' Digits 
    ; 

fragment 
Digits : ('0'..'9')+ 
    ; 

AxisName: 'ancestor' 
    | 'ancestor-or-self' 
    | 'attribute' 
    | 'child' 
    | 'descendant' 
    | 'descendant-or-self' 
    | 'following' 
    | 'following-sibling' 
    | 'namespace' 
    | 'parent' 
    | 'preceding' 
    | 'preceding-sibling' 
    | 'self' 
    ; 


    PATHSEP 
     :'/'; 
    ABRPATH 
     : '//'; 
    LPAR 
     : '('; 
    RPAR 
     : ')'; 
    LBRAC 
     : '['; 
    RBRAC 
     : ']'; 
    MINUS 
     : '-'; 
    PLUS 
     : '+'; 
    DOT 
     : '.'; 
    MUL 
     : '*'; 
    DOTDOT 
     : '..'; 
    AT 
     : '@'; 
    COMMA 
     : ','; 
    PIPE 
     : '|'; 
    LESS 
     : '<'; 
    MORE_ 
     : '>'; 
    LE 
     : '<='; 
    GE 
     : '>='; 
    COLON 
     : ':'; 
    CC 
     : '::'; 
    APOS 
     : '\''; 
    QUOT 
     : '\"'; 

Literal : '"' ~'"'* '"' 
    | '\'' ~'\''* '\'' 
    ; 

Whitespace 
    : (' '|'\t'|'\n'|'\r')+ ->skip 
    ; 

NCName : NCNameStartChar NCNameChar* 
    ; 

fragment 
NCNameStartChar 
    : 'A'..'Z' 
    | '_' 
    | 'a'..'z' 
    | '\u00C0'..'\u00D6' 
    | '\u00D8'..'\u00F6' 
    | '\u00F8'..'\u02FF' 
    | '\u0370'..'\u037D' 
    | '\u037F'..'\u1FFF' 
    | '\u200C'..'\u200D' 
    | '\u2070'..'\u218F' 
    | '\u2C00'..'\u2FEF' 
    | '\u3001'..'\uD7FF' 
    | '\uF900'..'\uFDCF' 
    | '\uFDF0'..'\uFFFD' 
// Unfortunately, java escapes can't handle this conveniently, 
// as they're limited to 4 hex digits. TODO. 
// | '\U010000'..'\U0EFFFF' 
    ; 

fragment 
NCNameChar 
    : NCNameStartChar | '-' | '.' | '0'..'9' 
    | '\u00B7' | '\u0300'..'\u036F' 
    | '\u203F'..'\u2040' 
    ; 
+1

Ссылка мертва, :( –

+0

@JimCounts Я уверен, что вы не ищите это через 4 года, но я только что обновил ответ с помощью рабочей ссылки. –

+0

@jwbroek вот ваш код :) – RobAu

2

я и написал XPath парсер и реализацию IXPathNavigable (я использовал, чтобы быть разработчиком для XMLPrime). Ничего нелегко; и я подозреваю, что IXPathNavigable не будет дешевой победой, на которую вы надеетесь, так как во взаимодействиях между различными методами довольно много тонкости - я подозреваю, что полный анализатор XPath будет проще (и более надежным).

Чтобы ответить на ваш вопрос, хотя:

var results xpathNavigable.CreateNavigator().Evaluate("/my/xpath[expression]"). 

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

Если вы всегда возвращали так, то все, что вы хотите знать о следующем XPath является то, что он ищет штриховые ребенок обув: foo[not(bar)]/other/elements

Если вы всегда возвращаете фиксированное число узлов, то вы никогда не знаете о большая часть этого XPath a[100]/b/c/

По существу, это не сработает.

 Смежные вопросы

  • Нет связанных вопросов^_^