2009-02-05 15 views
6

Estoy tratando de crear un 'AET' (árbol de expresiones abstractas) para XPath (ya que estoy escribiendo un editor WYSIWYG XSL). He estado golpeando mi cabeza contra la pared con el XPath BNF durante las últimas tres o cuatro horas.Expresiones Parse XPath

He pensado en otra solución. Pensé que podría escribir una clase que implementa IXPathNavigable, que devuelve un XPathNavigator propio cuando se llama a CreateNavigator. Este XPathNavigator siempre tendrá éxito en las llamadas a métodos, y hará un seguimiento de esas llamadas, por ejemplo. nos mudamos al nodo clientes y luego al nodo cliente. Podría usar esta información (con suerte) para crear el 'AET' (para que ahora tuviéramos clientes/clientes en un modelo de objetos).

La única pregunta es: ¿cómo en tierra hago funcionar un IXPathNavigable a través de un XPathExpression?

Sé que esto es excesivamente vago. Pero, ¿alguien más ha realizado el esfuerzo y ha escrito un analizador de expresiones XPath? Todavía no he considerado mi posible solución, porque no puedo probarla (porque no puedo ejecutar XPathExpression en un IXPathNavigable), así que ni siquiera sé si mi solución funcionará.

+0

El texto que comienza en IXPathNavigable es muy confuso. ¿Podrías editar la pregunta y explicar mejor? –

Respuesta

2

Hay una gramática xl de antlr here. Dado que su licencia lo permite, copié toda la gramática aquí para evitar la rotura del enlace en el futuro.

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

El enlace está muerto, :( –

+0

@JimCounts Estoy seguro de que no está buscando esto después de 4 años, pero acabo de actualizar la respuesta con un enlace de trabajo. –

+0

@jwbroek aquí está su código :) – RobAu

2

Lo he escrito un analizador XPath y una implementación de IXPathNavigable (solía ser un desarrollador de XMLPrime). Ninguno de los dos es fácil; y sospecho que IXPathNavigable no va a ser la ganancia barata que esperas, ya que hay mucha sutileza en las interacciones entre diferentes métodos. Sospecho que un analizador XPath completo será más simple (y más confiable).

Para responder a su pregunta, sin embargo:

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

lo que probablemente necesita para enumerar más resultados para hacer que el nodo a ser navegado.

Si siempre se devuelve cierto, entonces todo lo que sabría acerca de lo siguiente XPath es que se ve a los niños de la barra de Foo: foo[not(bar)]/other/elements

Si siempre devuelve un número fijo de nodos entonces nunca se sabe acerca la mayor parte de esta XPath a[100]/b/c/

Esencialmente, esto no funcionará.