XQuery, который выбирает узел, но не возвращает возвращаемые дочерние узлы - PullRequest
1 голос
/ 01 марта 2011

Я пытаюсь создать выражение xquery, которое будет возвращать выбранные узлы, но не будет возвращать их дочерние элементы. Это, вероятно, лучше всего иллюстрируется на примере. У меня есть следующий узел myNode:

<myNode>
  <myElements id="1">
    <myElement key="one">aaa</myElement>
    <myElement key="two" >bbb</myElement>
    <myElement key="three">ccc</myElement>
  </myElements>
  <myElements id="2">
    <myElement key="one">ddd</myElement>
    <myElement key="two" >eee</myElement>
    <myElement key="three">fff</myElement>
  </myElements>
</myNode>

Я заинтересован в возвращении узлов , но не ниже. Мой желаемый возврат будет выглядеть следующим образом:

<myNode>
  <myElements id="1" />
  <myElements id="2" />
</myNode>

или

<myNode>
  <myElements id="1"></myElements>
  <myElements id="2"></myElements>
</myNode>

В настоящее время у меня есть выражение xpath, которое будет выглядеть примерно так (упрощенно для этой иллюстрации), которое, как и ожидалось, возвращает потомки myElement:


$results/myNode/MyElements

Я лаю не на том дереве? Возможно ли это даже в XPath / XQuery?

Ответы [ 4 ]

3 голосов
/ 01 марта 2011

Попробуйте этот рекурсивный алгоритм ..

    xquery version "1.0";

    declare function local:passthru($x as node()) as node()* {   for $z in $x/node() return local:recurseReplace($z) };

    declare function local:recurseReplace($x as node()) {
        typeswitch ($x) 
            (: Changes based on a condition :)
            case element(myElements) return <myElements id="{$x/@id}" />
            (: IGNORE ANY CHANGES :)
            case text() return $x
            case comment() return comment {"an altered comment"}
            case element() return element {fn:node-name($x)} {for $a in $x/attribute()
                                                              return $a, local:passthru($x)}
            default return ()           
};

    let $doc := 
<myNode>   
  <myElements id="1">
        <myElement key="one">aaa</myElement>
        <myElement key="two" >bbb</myElement>
        <myElement key="three">ccc</myElement>   
  </myElements>   
  <myElements id="2">
        <myElement key="one">ddd</myElement>
        <myElement key="two" >eee</myElement>
        <myElement key="three">fff</myElement>   
  </myElements> 
</myNode> 
return local:recurseReplace($doc)
2 голосов
/ 02 марта 2011

XQuery - это , возвращающий только узлы верхнего уровня, он не возвращает их дочерние элементы. Но возвращенные узлы по-прежнему подключены к своим дочерним элементам, и любой код, отображающий результаты, выбирает отображение полного поддерева под узлами, которые вы фактически выбрали.

Поэтому первым шагом к пониманию вашей проблемы является осознание того, что вы не хотите, чтобы ваш запрос выбирал узлы из исходного документа, вы хотите, чтобы он создавал новые узлы, которые отличаются от оригинала наличием разных дочерних элементов.

Это означает, что это один из тех запросов, в которых вы хотите создать итоговый документ, который совпадает с оригиналом, но с небольшими изменениями. Как говорит Димитр, XSLT намного лучше в этом классе проблем, чем XQuery. Но это, безусловно, можно сделать с помощью XQuery, как показывает Скотт.

2 голосов
/ 01 марта 2011

XQuery значительно уступает XSLT для таких задач:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="myElements/node()"/>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному документу XML:

<myNode>
    <myElements id="1">
        <myElement key="one">aaa</myElement>
        <myElement key="two" >bbb</myElement>
        <myElement key="three">ccc</myElement>
    </myElements>
    <myElements id="2">
        <myElement key="one">ddd</myElement>
        <myElement key="two" >eee</myElement>
        <myElement key="three">fff</myElement>
    </myElements>
</myNode>

желаемый, правильный результат получается:

<myNode>
  <myElements id="1" />
  <myElements id="2" />
</myNode>

Объяснение : Правило идентификации, переопределенное для дочерних узлов myElements

0 голосов
/ 17 июня 2013

попробуй это самый короткий путь

let $a := 
<myNode>
  <myElements id="1">
    <myElement key="one">aaa</myElement>
    <myElement key="two" >bbb</myElement>
    <myElement key="three">ccc</myElement>
  </myElements>
  <myElements id="2">
    <myElement key="one">ddd</myElement>
    <myElement key="two" >eee</myElement>
    <myElement key="three">fff</myElement>
  </myElements>
</myNode>

for $e1 in $a
return element {name($e1)}
{
  for $e2 in $e1/*
  return element{name($e2)}{$e2/@*}
}
...