XPATH祖先或自我

时间:2012-11-13 06:28:42

标签: oracle xpath

Oracle数据库10g企业版10.2.0.5 - 64位

我正在尝试使用祖先或自我从元素输出hierarhy,但它根本不起作用:只打印所有元素(

嗯,我有什么:

1)像这样的XML文件。

<Root>
  <Element1 id="UniqueId1">
    <SubElement1 id="UniqueId2"/>
    <SubElement2 id="UniqueId3">
      <LeafElement1 id="UniqueId4"/>
      <LeafElement1 id="UniqueId5"/>
    </SubElement2>
  </Element1>
  <Element2 id="UniqueId6" AttributeToCheck="true">
    <SubElement1 id="UniqueId7">
      <LeafElement1 id="UniqueId8"/>
      <LeafElement1 id="UniqueId9"/>
    </SubElement1>
  </Element2> 
</Root>

2)我的XPATH字符串:

//*[@id and contains(@id, "UniqueId8")]/ancestor-or-self::*

3)我想得到这样的结果(从找到的元素到根):

<Root>
  <Element2 id="UniqueId6" AttributeToCheck="true">
    <SubElement1 id="UniqueId7">
      <LeafElement1 id="UniqueId8"/>
    </SubElement1>
  </Element2> 
</Root>

顺便说一句,// [@id and contains(@id,“UniqueId8”)] / ancestor-or-self :: / @ id工作正常。

有人知道如何解决这个问题或只是使用其他操作而不是祖先或自我?

更新:

我执行此操作:

DECLARE
  v_xml XMLTYPE;
BEGIN
    SELECT xmltype('<Root>
               <Element1 id="UniqueId1">
            <SubElement1 id="UniqueId2"/>                                           <SubElement2 id="UniqueId3">
                                            <LeafElement1 id="UniqueId4"/>
                                            <LeafElement1 id="UniqueId5"/>
                                        </SubElement2>
                                    </Element1>
                                    <Element2 id="UniqueId6" AttributeToCheck="true">
                                        <SubElement1 id="UniqueId7">
                                            <LeafElement1 id="UniqueId8"/>
                                            <LeafElement1 id="UniqueId9"/>
                                        </SubElement1>
                                    </Element2>
                                </Root>')
    into v_xml
    from dual;

    select extract(v_xml, '//*[@id="UniqueId9"]/ancestor-or-self::*')
    into v_xml
    from dual;

    dbms_output.put_line(v_xml.getStringVal());

END;

但结果我得到了一些奇怪的东西:

<Root>
  <Element1 id="UniqueId1">
              <SubElement1 id="UniqueId2"/>
            <SubElement2 id="UniqueId3">
                                     <LeafElement1 id="UniqueId4"/>
                                                 <LeafElement1 id="UniqueId5"/>
     </SubElement2>
    </Element1>
    <Element2 id="UniqueId6" AttributeToCheck="true">
    <SubElement1 id="UniqueId7">
    <LeafElement1 id="UniqueId8"/>
    <LeafElement1 id="UniqueId9"/>
    </SubElement1></Element2>
</Root>
<Element2 id="UniqueId6" AttributeToCheck="true">
    <SubElement1 id="UniqueId7">
        <LeafElement1 id="UniqueId8"/>
        <LeafElement1 id="UniqueId9"/>
    </SubElement1>
</Element2>

<SubElement1 id="UniqueId7">
    <LeafElement1 id="UniqueId8"/>
    <LeafElement1 id="UniqueId9"/>
</SubElement1>

<LeafElement1 id="UniqueId9"/>

4 个答案:

答案 0 :(得分:2)

XPath只允许您选择输入文档中的节点,它不允许您更改文档的结构或创建一个新节点,其中节点被更改(添加,删除,操作)。因此,一旦您使用路径表达式选择了根元素并输出结果,您当然会输出根元素及其包含的所有节点。

因此,XPath无法完成您想要的工作,因为您需要使用XQuery或XSLT;这样,您就可以创建一个包含您不想删除的节点的新文档。 Fragment input xhtml to seperate xhtml files with ancestor nodes deails是一个示例,其中XSLT用于过滤掉根元素的后代节点,这些节点不是祖先或某个节点的子节点。对于多个节点而言,它比您需要的更多,并创建了多个结果文档,但部分代码正在执行您想要的操作。我不知道你是否可以在Oracle的上下文中使用XSLT或XSLT 2.0所以我不会尝试将该代码调整到您的输入示例,除非您明确表示您可以使用XSLT以及您可以使用哪个版本的XSLT在Oracle的上下文中使用。

答案 1 :(得分:1)

正如Martin所说,你不能使用XPath来构造输入中不存在的树。

还有一点:请注意XPath表达式选择节点。可以将其视为返回输入文档中节点的一组指针。运行XPath查询的客户端环境通过显示以节点为根的子树来显示这些节点是很常见的。但是XPath表达式没有选择整个树,它只选择了根,节点下面的子树显示可能让你感到困惑。

答案 2 :(得分:1)

尝试这种XSL方法:

SQL> with xml as (select xmltype('<Root>
  2    <Element1 id="UniqueId1">
  3      <SubElement1 id="UniqueId2"/>
  4      <SubElement2 id="UniqueId3">
  5        <LeafElement1 id="UniqueId4"/>
  6        <LeafElement1 id="UniqueId5"/>
  7      </SubElement2>
  8    </Element1>
  9    <Element2 id="UniqueId6" AttributeToCheck="true">
 10      <SubElement1 id="UniqueId7">
 11        <LeafElement1 id="UniqueId8"/>
 12        <LeafElement1 id="UniqueId9"/>
 13      </SubElement1>
 14    </Element2>
 15  </Root>') xml from dual),
 16  xsl as (select xmltype('
 17  <xsl:stylesheet version="1.0"
 18   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 19   <xsl:template match="node()|@*">
 20    <xsl:copy>
 21     <xsl:apply-templates select="*[descendant-or-self::*[contains(@id,''UniqueId8'')]]|@*"/>
 22    </xsl:copy>
 23   </xsl:template>
 24  </xsl:stylesheet>') xsl from dual)
 25  select xm.xml.transform(xs.xsl)
 26    from xml xm, xsl xs;

XM.XML.TRANSFORM(XS.XSL)
--------------------------------------------------------------------------------

<Root>
 <Element2 id="UniqueId6" AttributeToCheck="true">
  <SubElement1 id="UniqueId7">
   <LeafElement1 id="UniqueId8">
   </LeafElement1>
  </SubElement1>
 </Element2>
</Root>

答案 3 :(得分:0)

带有 xtender 的家伙用XPATH找到了很好的解决方案,它确实有效:

   with t_xml as ( select xmltype('
    <Root>
      <Element1 id="UniqueId1">
        <SubElement1 id="UniqueId2"/>
        <SubElement2 id="UniqueId3">
          <LeafElement1 id="UniqueId4"/>
          <LeafElement1 id="UniqueId5"/>
        </SubElement2>
      </Element1>
      <Element2 id="UniqueId6" AttributeToCheck="true">
        <SubElement1 id="UniqueId7">
          <LeafElement1 id2="UniqueId8"/>
          <LeafElement1 id="UniqueId9"/>
        </SubElement1>
      </Element2> 
    </Root>') x from dual)
    select 
       t_xml.*
      ,updatexml(x,'//*[not (descendant-or-self::*[@id2="UniqueId8"])]',chr(10)) upd
    from t_xml