2016-05-21 12 views
1

Ich habe ein XML-Dokument wie unten. Ich versuche, Schlüssel/Wert-Paar für alle Elemente und Attribute auch zu erhalten. Die Abfrage, die ich habe, erhält alle Elementnamen und Elementwerte. Ich möchte jedoch auch Attributnamen und Attributwerte erhalten (vorzugsweise in derselben Abfrage, ansonsten in einer anderen Abfrage).Wie erweitert man eine Suche nach Elementen und Werten auf Attribute?

XML-Dokument:

 <bookstore> 
     <book category="COOKING"> 
      <title lang="en">Cook Book</title> 
      <author>Chef Author</author> 
      <year>2015</year> 
      <price>310.00</price> 
     </book> 
     <book category="CHILDREN"> 
      <title lang="en">Kid Story Book</title> 
      <author>KJ Banter</author> 
      <year>2010</year> 
      <price>229.99</price> 
     </book> 
     </bookstore> 

SQL-Abfrage in Oracle:

WITH tab AS 
    (SELECT xmltype(' 
       <bookstore> 
     <book category="COOKING"> 
      <title lang="en">Cook Book</title> 
      <author>Chef Author</author> 
      <year>2015</year> 
      <price>310.00</price> 
     </book> 
     <book category="CHILDREN"> 
      <title lang="en">Kid Story Book</title> 
      <author>KJ Banter</author> 
      <year>2010</year> 
      <price>229.99</price> 
     </book> 
     </bookstore> 
    ') col 
    FROM dual 
    ) 
    SELECT nodepath,nodevalue 
     FROM tab t, 
     xmltable(' 
     for $i in $tmp/descendant::* 
     where $i/text() != "" 
     return <R><P>{string-join($i/ancestor-or-self::*/name(), "/")}</P><V>{$i/text()}</V></R>' 
     passing t.col AS "tmp" columns 
     nodepath varchar2(1000) path '//P', 
     nodevalue varchar2(1000) path '//V') 

Antwort

1

Da Sie sie in der Reihenfolge des Dokuments wollen, steigen für jedes abgerufene Element und folgt seinem Selbst- und Attribute Achse. Sie müssen Element abrufen und Attributwerte unterschiedlich, so wenden Sie ein typeswitch:

for $node in /descendant::*/(., @*) 
let $value := (
    typeswitch ($node) 
    case element() return $node/text() 
    case attribute() return data($node) 
    default return() 
) 
where $value 
return <R> 
    <P>{ 
    string-join(($node/name(), $node/ancestor::*/name()), "/") 
    }</P> 
    <V>{ $value }</V> 
</R> 

Beachten Sie auch ich den ancestor-or-self Schritt zu einem ancestor Schritt geändert und ausdrücklich $node der Namen zurückgeben, damit wir müssen nicht unterscheiden zwischen Elemente und Attribute wieder in der ancestor Achse.

+0

Vielen Dank für die schnelle Antwort @Jens Erat. Als ich Ihre Lösung implementiert habe, erhalte ich die Fehlermeldung "ungültige Argumente für fn: data()". Ich bin neu bei xQuery. Ich glaube, ich muss etwas wie "return data ($ node/@ *)" und nicht "$ node/data()" verwenden. Ich konnte die Syntax nicht richtig herausfinden. Ich schätze deine Hilfe sehr. – Kumar99

+0

Es tut mir leid, ich habe einige XQuery 3.0 Notation/syntaktischen Zucker gemischt. Tauschen Sie einfach '$ node/data()' mit 'data ($ node)'. Ich habe meine Antwort entsprechend aktualisiert. –

+0

Irgendein Hintergrund warum '$ node/data()' nicht funktioniert, aber '$ node/text()' und '$ node/name()' do: '[fn:] data()' ist eine Funktion, während 'text()' und 'name()' sind Knotentests. Funktionen als Pfadschritte wurden in XQuery 3.0 hinzugefügt. –