【问题标题】:Retrieve value of an xml element in Oracle PL SQL在 Oracle PL SQL 中检索 xml 元素的值
【发布时间】:2010-10-19 02:04:26
【问题描述】:

有人知道如何使用 PL/SQL 检索 <ZIPCODE><CITY> 的值吗?我在网上遵循了一个教程,但是,它可以检索元素名称,但不能检索它们的值。你们中的任何人都知道似乎是什么问题吗?我已经就此咨询过谷歌(互联网保密),但没有运气:(

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

这是示例代码:

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

【问题讨论】:

  • 我个人更喜欢使用 XMLType 并使用 Extract 函数通过 XPath 获取它们。例如myxml.Extract('/Zipcodes/mappings/ZIPCODE/text()'); - 一定比遍历 DOM 更简单。

标签: sql xml oracle plsql


【解决方案1】:

你需要换行

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

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

在 XML DOM 中,元素没有任何“价值”可言。元素节点包含 Text 节点作为子节点,正是这些节点包含您想要的值。

编辑(回应 Tomalak 的评论):我不知道 DBMS_XMLDOM 中有任何函数可以获取元素的所有子文本节点的组合值。如果这就是您所需要的,那么您可能需要使用以下函数:

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

【讨论】:

  • 如果一个节点包含多个后代怎么办 - 你如何获得它们的组合文本?
  • 感谢您抽出宝贵时间,我已经 +1 了。但是 - 这不应该以某种方式递归吗?也许 XPath 是更合适的选择? (我承认我对 Oracle 了解不多,所以我不知道进行 XPath 查询需要什么。)
  • 通过在 IF 块中添加 ELSIF 子句,可以轻松地使上述函数递归。这是否值得做取决于OP需要什么。 XPath 是可能的,但是我的同事在使用 Oracle XML DB(尤其是使用 XSLT)时遇到了可靠性问题,所以我不想那样做。
  • DBMS_XMLDOM.CDATA_SECTION_NODE 怎么样?
  • 还有一个函数 dbms_xslprocessor.valueOf(...),但是,在 Oracle 9i 中它不能很好地处理 XPath 查询。例如。 XPath 表达式 '/a//text()' 或 'string(/a)' 不能正常工作。 (注意 XPath 'string(/a)' 应该和上面的 f_get_text_content 一样。
【解决方案2】:

这是如何从文档中检索所需值的简单说明:

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;

上面的结果是请求的输出:

94301
Palo Alto

将上面示例中的 xpath 模式替换为 pattern => '//text()' 会导致输出:

CA
94301
Palo Alto

即。文档中的所有文本。使用这种技术当然可以对这个主题进行许多变体。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 2013-07-30
    • 2012-08-15
    • 1970-01-01
    • 2013-07-07
    • 1970-01-01
    相关资源
    最近更新 更多