2012-09-02 10 views
6

Estoy tratando de escribir un Xpath Statement (1.0) que pueda leer información de un nodo 'search' y realizar una búsqueda utilizándolo.¿Cómo puedo usar la función Xpath 'contains()' para no devolver nada si su param de búsqueda está en blanco o falta/es falso?

Estaba haciendo un buen progreso, pero tropecé con un problema donde si un atributo (utilizado para un valor en la búsqueda) está vacío o no existe, falla. Ejemplo

código editado para simplificar:

Así que aquí está mi XML de ejemplo:

<xml> 
    <files> 
     <file name="foo" description="" rating="4"/> 
     <file name="food" description="" rating="4"/> 
     <file name="foobar" description="" rating="3"/> 
     <file name="bar" description="" rating="3"/> 
     <file name="barter" description="" rating="3"/> 
     <file name="barterer" description="" rating="2"/> 
    </files> 
    <searches> 
     <search id="1"> 
      <exclude> 
       <file term="foo"/> 
      </exclude> 
     </search> 
    </searches> 
</xml> 

y XPath de trabajo:

//files/file[ 
      not(contains(@name, //search[@id='1']/exclude/file/@term)) 
] 

Funciona como se esperaba ...

Sin embargo, si el atributo esperado i falta o está vacío, no funcionará. Creo que porque: contains (@attrib, "") concuerda con todo por alguna razón, por lo tanto, un not() siempre no coincidirá con nada si el atributo es "" o no está presente.

Por ejemplo, si altero el fragmento excluir de XML a esta falla:

  <exclude> 
       <file term=""/> 
      </exclude> 

con esto también:

  <exclude></exclude> 

¿Hay alguna forma de comprobar un valor vacío y no realizar la selección? o quizás haya una mejor forma de estructurar la Lógica. Sin tener en cuenta que no puedo usar Conditionals o las otras funciones en Xpath2.0.

+0

¿Podría, por favor, edite la cuestión y describir las reglas para encontrar una coincidencia de búsqueda - estos no son proporcionados y la expresión XPath larga es bastante confusa - Sospecho que se puede usar una expresión más corta. Por ejemplo: 'cond1 y cond2 o cond1 o cond2' pueden simplemente ser sustituidos por la expresión equivalente más corta' cond1 o cond2'. –

+0

Perdón por eso. Actualicé los ejemplos del Código para señalar más claramente mi problema. – Futile32

+0

@ Futile32, tal vez tu XPath obtenga los nodos con name = "", y como no tienes ninguno, no obtienes ninguno. –

Respuesta

0

Así que tropezó con la respuesta en una publicación diferente A continuación hay un ejemplo de cómo funciona. Gracias por el consejo de todos.

//files/file[ 
    not(
     contains(
      @name, 
      concat(//search[@id='1']/exclude/file/@term, 
       substring('??', 1 + 2* 
        boolean(substring(//search[@id='1']/exclude/file/@term, 1)) 
       ) 
      ) 
     ) 
    ) 
] 

El bit donde coloqué "??" Probablemente quiera reemplazar con un char inválido o algo así. Para cada carácter adicional utilizado, el 1+ necesita incrementarse. Para mí, estoy revisando los nombres de los archivos, por lo que un questionmark me parece una buena idea. Para ser sincero, probablemente no usaré esta ruta, estaba ansioso por resolver el problema después de todo este tiempo.

Aquí es donde me ocurrió la idea de: How to give back constant if node does not exist in XPATH?

2

¿Por qué la función Xpath contiene() devuelve todo si busca param está en blanco o falta?

Porque eso es lo que dice la especificación XPath la función contains() debe hacer:

Si el valor de $ arg2 es la cadena de longitud cero, entonces la función retorna verdadero .

Se podría ajustar su XPath y simplificar algunas de las condiciones con lo siguiente:

//files/file[ 
      ( 
       (
        not(//search[@id='1']/include/file/@term) 
        or 
        (
        contains(@name, //search[@id='1']/include/file/@term) 
        or 
        contains(@description, //search[@id='1']/include/file/@term) 
        ) 
       ) 
       or 
       contains(@rating, //search[@id='1']/include/file/@rating) 
      )  
      and 
      ( 
       (
        not(//search[@id='1']/exclude/file/@term) 
        or 
        (
        not(contains(@name, //search[@id='1']/exclude/file/@term)) 
        and 
        not(contains(@description, //search[@id='1']/exclude/file/@term)) 
        ) 
       ) 
       and 
       (
        not(//search[@id='1']/exclude/file/@rating) 
        or 
        not(contains(@rating, //search[@id='1']/exclude/file/@rating)) 
       ) 
      ) 

      ] 
+0

Gracias por la referencia, sin embargo, creo que esperaba encontrar una forma de poder usar la función de manera diferente para resolver mi problema. He reescrito mi pregunta para indicar eso. – Futile32

0

Tal vez usted quiere decir algo así como

//files/file[ 
    not(contains(@name, 
       //search[@id='1'] 
       /exclude/file/@term)) 
    or not(
    normalize-string(//search[@id='1'] 
         /exclude/file/@term) 
    ) 
] 
Cuestiones relacionadas