Pregunta Predicado XPath con subrutas con lxml?


Estoy tratando de entender y XPath que me fue enviado para usar con los formularios ACORD XML (formato común en el seguro). El XPath que me enviaron es (truncado por brevedad):

./PersApplicationInfo/InsuredOrPrincipal[InsuredOrPrincipalInfo/InsuredOrPrincipalRoleCd="AN"]/GeneralPartyInfo

Donde me estoy metiendo en problemas es que Python lxml biblioteca me está diciendo eso [InsuredOrPrincipalInfo/InsuredOrPrincipalRoleCd="AN"] es un invalid predicate. No puedo encontrar nada en el Especificación XPath en predicados que identifica esta sintaxis para que pueda modificar este predicado para que funcione.

¿Hay alguna documentación sobre qué es exactamente lo que este predicado está seleccionando? Además, ¿esto es incluso un predicado válido, o algo ha sido mutilado en alguna parte?

Posiblemente relacionado:

Creo que la empresa con la que estoy trabajando es una tienda de MS, por lo que esta XPath puede ser válida en C # o en algún otro idioma de esa pila. No estoy del todo seguro.

Actualizaciones:

Por demanda de comentarios, aquí hay información adicional.

Muestra XML:

<ACORD>
  <InsuranceSvcRq>
    <HomePolicyQuoteInqRq>
      <PersPolicy>
        <PersApplicationInfo>
            <InsuredOrPrincipal>
                <InsuredOrPrincipalInfo>
                    <InsuredOrPrincipalRoleCd>AN</InsuredOrPrincipalRoleCd>
                </InsuredOrPrincipalInfo>
                <GeneralPartyInfo>
                    <Addr>
                        <Addr1></Addr1>
                    </Addr>
                </GeneralPartyInfo>
            </InsuredOrPrincipal>
        </PersApplicationInfo>
      </PersPolicy>
    </HomePolicyQuoteInqRq>
  </InsuranceSvcRq>
</ACORD>

Ejemplo de código (con XPath completo en lugar de fragmento):

>>> from lxml import etree
>>> tree = etree.fromstring(raw)
>>> tree.find('./InsuranceSvcRq/HomePolicyQuoteInqRq/PersPolicy/PersApplicationInfo/InsuredOrPrincipal[InsuredOrPrincipalInfo/InsuredOrPrincipalRoleCd="AN"]/GeneralPartyInfo/Addr/Addr1')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "lxml.etree.pyx", line 1409, in lxml.etree._Element.find (src/lxml/lxml.etree.c:39972)
  File "/Library/Python/2.5/site-packages/lxml-2.3-py2.5-macosx-10.3-i386.egg/lxml/_elementpath.py", line 271, in find
    it = iterfind(elem, path, namespaces)
  File "/Library/Python/2.5/site-packages/lxml-2.3-py2.5-macosx-10.3-i386.egg/lxml/_elementpath.py", line 261, in iterfind
    selector = _build_path_iterator(path, namespaces)
  File "/Library/Python/2.5/site-packages/lxml-2.3-py2.5-macosx-10.3-i386.egg/lxml/_elementpath.py", line 245, in _build_path_iterator
    selector.append(ops[token[0]](_next, token))
  File "/Library/Python/2.5/site-packages/lxml-2.3-py2.5-macosx-10.3-i386.egg/lxml/_elementpath.py", line 207, in prepare_predicate
    raise SyntaxError("invalid predicate")
SyntaxError: invalid predicate

7
2018-06-02 17:40


origen


Respuestas:


Cambio tree.find a tree.xpath. find y findall están presentes en lxml para proporcionar compatibilidad con otras implementaciones de ElementTree. Estos métodos no implementan todo el lenguaje XPath. Para emplear expresiones XPath que contengan características más avanzadas, use la xpath método, el XPath clase, o XPathEvaluator.

Por ejemplo:

import io
import lxml.etree as ET

content='''\
<ACORD>
  <InsuranceSvcRq>
    <HomePolicyQuoteInqRq>
      <PersPolicy>
        <PersApplicationInfo>
            <InsuredOrPrincipal>
                <InsuredOrPrincipalInfo>
                    <InsuredOrPrincipalRoleCd>AN</InsuredOrPrincipalRoleCd>
                </InsuredOrPrincipalInfo>
                <GeneralPartyInfo>
                    <Addr>
                        <Addr1></Addr1>
                    </Addr>
                </GeneralPartyInfo>
            </InsuredOrPrincipal>
        </PersApplicationInfo>
      </PersPolicy>
    </HomePolicyQuoteInqRq>
  </InsuranceSvcRq>
</ACORD>
'''
tree=ET.parse(io.BytesIO(content))
path='//PersApplicationInfo/InsuredOrPrincipal[InsuredOrPrincipalInfo/InsuredOrPrincipalRoleCd="AN"]/GeneralPartyInfo'
result=tree.xpath(path)
print(result)

rendimientos

[<Element GeneralPartyInfo at b75a8194>]

mientras tree.find rendimientos

SyntaxError: invalid node predicate

18
2018-06-03 18:17



Tu ejemplo está perfectamente bien en mi opinión. Verificaría si la implementación de lxmls XPath tiene algunas limitaciones documentadas o algo así.


3
2018-06-02 17:50



./PersApplicationInfo/InsuredOrPrincipal
                 [InsuredOrPrincipalInfo/InsuredOrPrincipalRoleCd="AN"]
                     /GeneralPartyInfo/

Algunos problemas con esta expresión:

  1. El final / carácter lo hace sintácticamente inválido. Marca el inicio de un nuevo paso de ubicación, pero no sucede nada.

  2. Como notó el Dr. Michael Kay, es posible que tengas problemas con las comillas anidadas en Python.

Solución sugerida:

./PersApplicationInfo/InsuredOrPrincipal
                 [InsuredOrPrincipalInfo/InsuredOrPrincipalRoleCd='AN']
                     /GeneralPartyInfo

En esta expresión, las comillas dobles se reemplazan por comillas simples. El segundo cambio es la eliminación del final / personaje.

Actualizar: Ahora que el OP ha proporcionado un ejemplo de código más completo, puedo verificar que no haya nada de malo con la expresión XPath real utilizada. Debajo está su verificación con XSLT:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:template match="/*">
  <xsl:copy-of select=
  './InsuranceSvcRq/HomePolicyQuoteInqRq/PersPolicy
                 /PersApplicationInfo/InsuredOrPrincipal
                     [InsuredOrPrincipalInfo/InsuredOrPrincipalRoleCd="AN"]
                                                   /GeneralPartyInfo/Addr/Addr1'/>
 </xsl:template>
</xsl:stylesheet>

cuando esta transformación se aplica en el documento XML provisto:

<ACORD>
    <InsuranceSvcRq>
        <HomePolicyQuoteInqRq>
            <PersPolicy>
                <PersApplicationInfo>
                    <InsuredOrPrincipal>
                        <InsuredOrPrincipalInfo>
                            <InsuredOrPrincipalRoleCd>AN</InsuredOrPrincipalRoleCd>
                        </InsuredOrPrincipalInfo>
                        <GeneralPartyInfo>
                            <Addr>
                                <Addr1></Addr1>
                            </Addr>
                        </GeneralPartyInfo>
                    </InsuredOrPrincipal>
                </PersApplicationInfo>
            </PersPolicy>
        </HomePolicyQuoteInqRq>
    </InsuranceSvcRq>
</ACORD>

el resultado deseado y correcto es producido:

<Addr1 />

Conclusión: El problema está en el uso del código Python, o (menos probable) que el motor XPath usado tiene un error.


1
2018-06-03 13:22



El XPath que te dieron es perfectamente correcto. Tal vez el problema surgió al incrustarlo en Python, donde tendrá que usar las convenciones de escape de Python para escapar de las comillas dobles en una cadena de caracteres.


0
2018-06-03 07:10