2012-09-02 6 views
6

Ich versuche eine Xpath-Anweisung (1.0) zu schreiben, die Informationen von einem "Such" -Knoten lesen und eine Suche damit durchführen kann.Wie kann ich die Xpath-Funktion 'contains()' verwenden, um nichts zurückzugeben, wenn der Suchparameter leer ist oder fehlt/false?

Ich machte einige nette Fortschritte, stieß aber auf ein Problem, wo, wenn ein Attribut (für einen Wert in der Suche verwendet) leer ist oder nicht existiert, schlägt es fehl.

-Code Edited zu vereinfachen Beispiel:

So Hier ist mein Beispiel XML:

<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> 

und Arbeits XPATH:

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

Es funktioniert wie erwartet ...

Wenn jedoch das erwartete Attribut i s fehlt oder leer es wird nicht funktionieren. Ich denke, weil: enthält (@attrib, "") passt alles aus irgendeinem Grund, daher wird ein not() immer nichts zusammen, wenn das Attribut "" oder nicht vorhanden ist.

Zum Beispiel, wenn ich das ausschließen Fragment von XML dies ändern scheitert es:

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

mit diesem zu:

  <exclude></exclude> 

Gibt es eine Möglichkeit für einen leeren Wert zu prüfen und nicht die Auswahl durchführen? Oder gibt es vielleicht einen besseren Weg, die Logik zu strukturieren? Ich kann nicht Conditionals oder die anderen Funktionen in Xpath2.0 verwenden.

+0

Könnten Sie bitte, bearbeiten Sie die Frage und die Regeln beschreiben für eine Suche Spiel zu finden - diese werden nicht zur Verfügung gestellt und den langen XPath-Ausdruck ist ziemlich verwirrend - Ich vermute, dass ein kürzerer Ausdruck verwendet werden kann. Zum Beispiel: 'cond1 und cond2 oder cond1 oder cond2' kann einfach durch den kürzeren, äquivalenten Ausdruck' cond1 oder cond2' ersetzt werden. –

+0

Entschuldigung. Ich habe die Code-Beispiele aktualisiert, um deutlicher auf mein Problem hinzuweisen. – Futile32

+0

@ Futile32, vielleicht bekommt Ihr XPath die Knoten mit name = "", und weil Sie keine leer haben, bekommen Sie keine. –

Antwort

0

sagen möchte So stolperte ich über die Antwort in ein anderer Beitrag. Unten ist ein Beispiel dafür, wie es funktioniert. Danke für die Beratung.

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

Das Bit, wo ich "??" möchte wahrscheinlich mit einem ungültigen Zeichen oder etwas ersetzen. Für jedes zusätzliche Zeichen muss 1+ erhöht werden. Für mich überprüfe ich Dateinamen, so scheint ein Fragezeichen eine gute Idee. Um ehrlich zu sein, werde ich wahrscheinlich diese Route nicht benutzen, ich war nur bestrebt, das Problem nach all der Zeit zu lösen.

Hier ist, wo ich die Idee von bekam: How to give back constant if node does not exist in XPATH?

2

Warum gibt die Xpath-Funktion() alles zurück, wenn es sucht Parameter ist leer oder fehlt?

Denn das ist, was die XPath-Spezifikation sagt die contains() Funktion tun soll:

Wenn der Wert von $ arg2 ist die Zeichenfolge der Länge Null, dann ist die Funktion gibt true zurück.

Sie Ihre XPath anpassen könnte und einige der Bedingungen der folgenden vereinfachen:

//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

Danke für die Referenz, aber ich glaube, ich hatte gehofft, einen Weg zu finden, ich kann die Funktion anders nutzen, um mein Problem zu lösen. Ich habe meine Frage umformuliert, um das anzuzeigen. – Futile32

0

Vielleicht haben Sie so etwas wie

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