2009-04-13 11 views
6

Qualcuno sa come recuperare i valori di <ZIPCODE> e <CITY> utilizzando PL/SQL? Ho seguito un tutorial sulla rete, tuttavia, è in grado di recuperare i nomi degli elementi, ma non i loro valori. Qualcuno di voi sa quale sembra essere il problema? Ho già consultato Google (ben tenuto segreto di Internet) su questo, ma senza fortuna :(Recupera il valore di un elemento xml in Oracle PL SQL

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

ecco il codice di esempio:

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

Personalmente preferisco utilizzare XMLType e utilizzare la funzione Estrai per ottenerli tramite XPath. per esempio. 'myxml.Extract ('/ Zipcodes/mappings/ZIPCODE/text()');' - deve essere più semplice di camminare sul DOM. –

risposta

12

È necessario modificare la linea

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

a

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

In DOM XML, gli elementi non hanno alcun "valore" di cui parlare. I nodi elemento contengono nodi di testo come elementi secondari e sono questi nodi che contengono i valori desiderati.

EDIT (in risposta al commento di Tomalak): Non sono a conoscenza di alcuna funzione in DBMS_XMLDOM per ottenere il valore combinato di tutti i nodi di testo figlio di un elemento. Se questo è quello che vi serve, allora si può anche bisogno di usare qualcosa come la seguente funzione:

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

Cosa succede se un nodo contiene più discendenti? Come si ottiene il loro testo combinato? – Tomalak

+2

Grazie per aver dedicato del tempo, ho già dato il mio +1 in precedenza. Tuttavia - non dovrebbe essere ricorsivo in qualche modo? Forse XPath è una scelta più appropriata? (In realtà non conosco molto su Oracle, quindi non ho idea di cosa sia necessario fare query XPath.) – Tomalak

+0

La funzione sopra descritta può essere facilmente ricorsiva aggiungendo una clausola ELSIF al blocco IF. Se ciò valga la pena, dipende da cosa ha bisogno l'OP. XPath è possibile, tuttavia i miei colleghi hanno avuto problemi di affidabilità con Oracle XML DB (specialmente con XSLT) quindi preferirei non andare in quel modo. –

0

Questo è un semplice esempio di come recuperare i valori desiderati dal documento:

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; 

Il succitati la potenza richiesta:

94301 
Palo Alto 

Sostituzione del modello xpath nell'esempio precedente con pattern => '// text()' risultati nell'output:

CA 
94301 
Palo Alto 

ie. tutto il testo nel documento. Molte varianti su questo tema sono ovviamente possibili utilizzando questa tecnica.