选择节点但忽略返回子节点的 XQuery

发布于 2024-10-19 16:20:58 字数 1063 浏览 6 评论 0原文

我正在尝试创建一个 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 中是否可能?

I'm attempting to create an xquery expression that will return selected nodes but will not return their children. This is probably best illustrated with an example. I have the following myNode node:

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

I am interested in returning the <myElements > nodes, but nothing lower. My desired return would look like the following:

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

or

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

I currently have a xpath expression that would look something like the following (simplified for this illustration), which as expected, is returning the myElement children:


$results/myNode/MyElements

Am I barking up the wrong tree? Is this even possible in XPath/XQuery?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

如梦亦如幻 2024-10-26 16:20:58

尝试这个递归算法..

    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)

Try this recursive algorithm..

    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)
沧笙踏歌 2024-10-26 16:20:58

对于此类任务,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 的子节点

XQuery is quite inferior to XSLT for such tasks:

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

when this transformation is applied on the provided XML document:

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

the wanted, correct result is produced:

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

Explanation: The identity rule, overriden for child nodes of myElements

烙印 2024-10-26 16:20:58

XQuery仅返回顶级节点,而不返回其子节点。但是返回的节点仍然连接到它们的子节点,并且无论显示结果的代码是什么,都选择在您实际选择的节点下显示完整的子树。

因此,理解问题的第一步是认识到您不希望查询从源文档中选择节点,而是希望它通过具有不同的子节点来构造与原始节点不同的新节点。

这意味着它是您想要生成与原始文件相同但有一些小更改的结果文档的查询之一。正如 Dimitre 所说,XSLT 在解决此类问题上比 XQuery 好得多。但正如 Scott 所示,这当然可以通过 XQuery 来完成。

XQuery is only returning the top level nodes, it is not returning their children. But the returned nodes are still connected to their children, and whatever code it is that is displaying the results is choosing to display the full subtree under the nodes that you actually selected.

The first step to understanding your problem is therefore to realise that you don't want you query to select nodes from the source document, you want it to construct new nodes that differ from the original by having different children.

This means it's one of those queries where you want to produce a result document that is the same as the original but with a few small changes. As Dimitre says, XSLT is much better at this class of problem than XQuery. But it can certainly be done with XQuery, as Scott shows.

晚风撩人 2024-10-26 16:20:58

尝试这是最短的方法

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/@*}
}

try this is the shortest way

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/@*}
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文