2009-04-13 6 views
6

Est-ce que quelqu'un sait comment récupérer les valeurs de <ZIPCODE> et <CITY> en utilisant PL/SQL? J'ai suivi un tutoriel sur le net, cependant, il peut récupérer les noms des éléments, mais pas leurs valeurs. L'un d'entre vous sait ce qui semble être le problème? Je l'ai déjà consulté Google (le secret bien gardé Internet) sur cela, mais pas de chance :(Récupérer la valeur d'un élément XML dans Oracle PL SQL

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

est ici l'exemple de code:

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

Personnellement, je préfère utiliser XMLType et utiliser la fonction Extract pour les obtenir via XPath. par exemple. 'myxml.Extract ('/ Zipcodes/mappings/ZIPCODE/text()');' - doit être plus simple que de marcher sur le DOM. –

Répondre

12

Vous devez changer la ligne

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

à

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

Dans XML DOM, les éléments n'ont pas de 'valeur' ​​à proprement parler. Les nœuds d'élément contiennent des nœuds de texte en tant qu'enfants et ce sont ces nœuds qui contiennent les valeurs souhaitées.

EDIT (en réponse au commentaire de Tomalak): Je ne connais aucune fonction dans DBMS_XMLDOM pour obtenir la valeur combinée de tous les nœuds de texte enfant d'un élément. Si c'est ce que vous avez besoin, vous pouvez bien avoir besoin d'utiliser quelque chose comme la fonction suivante:

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

Et si un noeud contient plusieurs descendants - comment obtenez-vous leur texte combiné? – Tomalak

+2

Merci d'avoir pris le temps, j'ai déjà donné mon +1 plus tôt. Cependant - ne devrait-il pas être récursif d'une certaine façon? Peut-être que XPath est un choix plus approprié? (Je ne connais pas grand chose d'Oracle, donc je n'ai aucune idée de ce qui est requis pour faire des requêtes XPath.) – Tomalak

+0

La fonction ci-dessus peut facilement être rendue récursive en ajoutant une clause ELSIF au bloc IF. Cela dépend de ce dont le PO a besoin. XPath est possible, mais mes collègues ont eu des problèmes de fiabilité avec Oracle XML DB (en particulier avec XSLT) donc je préfère ne pas aller de cette façon. –

0

Ceci est une simple illustration de la façon de récupérer les valeurs souhaitées du document:

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; 

Le au-dessus des résultats de la sortie souhaitée:

94301 
Palo Alto 

Remplacement du motif XPath dans l'exemple ci-dessus avec motif => « // texte() » dans les résultats de la sortie:

CA 
94301 
Palo Alto 

ie. tout le texte dans le document. De nombreuses variations sur ce thème sont bien sûr possibles en utilisant cette technique.

Questions connexes