2009-04-13 11 views
6

Weiß jemand, wie die Werte von <ZIPCODE> abzurufen und <CITY> mit PL/SQL? Ich habe ein Tutorial über das Netz verfolgt, aber es kann die Elementnamen abrufen, aber nicht ihre Werte. Jeder von euch weiß, was das Problem zu sein scheint? Ich habe bereits angehört Google (das gut gehütete Geheimnis Internet) über das aber kein Glück :(in Oracle PL SQL

<Zipcodes> 
    <mappings Record="4"> 
    <STATE_ABBREVIATION>CA</STATE_ABBREVIATION> 
    <ZIPCODE>94301</ZIPCODE> 
    <CITY>Palo Alto</CITY> 
    </mappings> 
</Zipcodes> 

hier ist der Beispielcode:

-- prints elements in a document 
PROCEDURE printElements(doc DBMS_XMLDOM.DOMDocument) IS 
    nl DBMS_XMLDOM.DOMNodeList; 
    n DBMS_XMLDOM.DOMNode; 
    len number; 
BEGIN 
    -- get all elements 
    nl := DBMS_XMLDOM.getElementsByTagName(doc, '*'); 

    len := DBMS_XMLDOM.getLength(nl); 

    -- loop through elements 
    FOR i IN 0 .. len - 1 LOOP 
     n := DBMS_XMLDOM.item(nl, i); 

     testr := DBMS_XMLDOM.getNodeName(n) || ' ' || DBMS_XMLDOM.getNodeValue(n); 

     DBMS_OUTPUT.PUT_LINE (testr); 
    END LOOP; 

    DBMS_OUTPUT.PUT_LINE (''); 
END printElements; 
+0

Ich ziehe XMLType zu verwenden und die Extract-Funktion verwenden, um sie über XPath zu bekommen. z.B. 'myxml.Extract ('/ Zipcodes/mappings/ZIPCODE/text()');' - muss einfacher als das DOM gehen. –

Antwort

12

Sie müssen die Linie

testr := DBMS_XMLDOM.getNodeName(n) || ' ' || DBMS_XMLDOM.getNodeValue(n); 
ändern

bis

testr := DBMS_XMLDOM.getNodeName(n) || ' ' || DBMS_XMLDOM.getNodeValue(DBMS_XMLDOM.getFirstChild(n)); 

In XML-DOM, Elemente haben keinen "Wert", von dem man sprechen kann. Elementknoten enthalten Textknoten als untergeordnete Elemente, und diese Knoten enthalten die gewünschten Werte.

BEARBEITEN (als Antwort auf Tomalaks Kommentar): Mir sind keine Funktionen in DBMS_XMLDOM bekannt, um den kombinierten Wert aller untergeordneten Textknoten eines Elements zu erhalten. Wenn das, was Sie brauchen, dann können Sie auch so etwas wie die folgende Funktion verwenden müssen:

CREATE OR REPLACE FUNCTION f_get_text_content (
    p_node   DBMS_XMLDOM.DOMNode 
) RETURN VARCHAR2 
AS 
    l_children  DBMS_XMLDOM.DOMNodeList; 
    l_child   DBMS_XMLDOM.DOMNode; 
    l_text_content VARCHAR2(32767); 
    l_length   INTEGER; 
BEGIN 
    l_children := DBMS_XMLDOM.GetChildNodes(p_node); 
    l_length := DBMS_XMLDOM.GetLength(l_children); 
    FOR i IN 0 .. l_length - 1 LOOP 
    l_child := DBMS_XMLDOM.Item(l_children, i); 
    IF DBMS_XMLDOM.GetNodeType(l_child) IN (DBMS_XMLDOM.TEXT_NODE, DBMS_XMLDOM.CDATA_SECTION_NODE) THEN 
     l_text_content := l_text_content || DBMS_XMLDOM.GetNodeValue(l_child); 
    END IF; 
    END LOOP; 
    RETURN l_text_content; 
END f_get_text_content; 
/
+0

Was ist, wenn ein Knoten mehrere Nachkommen enthält - wie erhalten Sie ihren kombinierten Text? – Tomalak

+2

Danke, dass du dir die Zeit genommen hast, ich habe meine +1 schon früher gegeben. Allerdings - sollte das nicht in irgendeiner Weise rekursiv sein? Vielleicht ist XPath eine geeignetere Wahl? (Ich zugegebenermaßen nicht wissen viel über Oracle, so habe ich keine Ahnung, was erforderlich ist XPath-Abfragen zu tun.) – Tomalak

+0

Die obige Funktion leicht gemacht rekursive werden kann durch Zugabe eines ELSIF Klausel in den Block IF. Ob sich dies lohnt, hängt davon ab, was das OP braucht. XPath ist möglich, aber Kollegen von mir hatten Zuverlässigkeitsprobleme mit Oracle XML DB (besonders mit XSLT), also würde ich lieber nicht auf diese Weise gehen. –

0

Dies ist ein einfaches Beispiel dafür, wie die gewünschten Werte aus dem Dokument abzurufen:

declare 
    vDOM  dbms_xmldom.DOMDocument; 
    vNodes dbms_xmldom.DOMNodeList; 
    vXML  xmltype := xmltype('<Zipcodes> 
    <mappings Record="4"> 
    <STATE_ABBREVIATION>CA</STATE_ABBREVIATION> 
    <ZIPCODE>94301</ZIPCODE> 
    <CITY>Palo Alto</CITY> 
    </mappings> 
</Zipcodes>'); 
begin 
    -- create the dom document from our example xmltype 
    vDOM := dbms_xmldom.newDOMDocument(vXML); 
    -- find all text nodes in the dom document and return them into a node list 
    vNodes := dbms_xslprocessor.selectNodes 
       (n   => dbms_xmldom.makeNode(dbms_xmldom.getDocumentElement(vDOM)) 
       ,pattern => '//*[self::ZIPCODE or self::CITY]/text()' 
       ,namespace => null 
      ); 
    -- iterate through the node list 
    for i in 0 .. dbms_xmldom.getlength(vNodes) - 1 loop 
    -- output the text value of each text node in the list 
    dbms_output.put_line(dbms_xmldom.getNodeValue(dbms_xmldom.item(vNodes,i))); 
    end loop; 
    -- free up document resources 
    dbms_xmldom.freeDocument(vDOM);  
end; 

Die obige Ergebnisse in der Ausgabe angefordert:

94301 
Palo Alto 

XPath-Muster in dem obigen Beispiel mit Mustern ersetzen => '// text()' Ergebnisse in der Ausgabe:

CA 
94301 
Palo Alto 

dh. der gesamte Text im Dokument. Mit dieser Technik sind natürlich viele Variationen dieses Themas möglich. Persönlich