【问题标题】:How to return the full document using xdmp:node-replace()?如何使用 xdmp:node-replace() 返回完整文档?
【发布时间】:2018-11-29 10:49:24
【问题描述】:

我有一个要求,我需要在所有过程完成后最后返回完整的文档。

我的最后一条语句有一个xdmp:node-replace(),因此它返回一个empty sequence

节点在我的最终文档中被替换,但我无法在第一次运行时在控制台上看到它们。当我第二次运行它时,我可以看到被替换的节点。

这里是示例代码-

abc.xml--->
  <root>
       <id>abcd</id>
  </root>

let $doc := doc("abc.xml")
 (: Let $doc is having an Id node :)

let $replace := xdmp:node-replace($doc//id,<id>1234</id>)
  return $doc

Actual Output-->
 <root>
       <id>abcd</id>
  </root>

 Expected Output-->
   <root>
       <id>1234</id>
  </root>

如果我返回$replace,那么它会给我empty sequence

我想在第一次运行时返回预期的输出

有什么建议吗?

【问题讨论】:

    标签: xquery marklogic


    【解决方案1】:

    xdmp:node-replace 替换数据库中的节点,而不是内存中的节点。此外,您在提交之前看不到数据库更新。

    一个简单的解决方案是创建一个更新的内存文档并将其返回。

    xquery version "1.0-ml";
    
    xdmp:document-insert("abc.xml",
    <root>
      <id>abcd</id>
      <name>Test</name>
    </root>
    );
    
    let $doc := doc("abc.xml")
    let $update := 
    <root>
        <id>1234</id>
        {$doc/root/name}
    </root>
    
    return (
      xdmp:document-insert("abc.xml", $update), 
      $update
    )
    

    编辑:

    使用内存替换功能的替代方案:

    xquery version "1.0-ml";
    
    import module namespace mem = "http://xqdev.com/in-mem-update" at '/MarkLogic/appservices/utils/in-mem-update.xqy';
    
    let $doc := doc("abc.xml")
    let $updatedDoc := mem:node-replace($doc//id, <id>1234</id>)
    
    return (
      xdmp:node-replace($doc, $updatedDoc),
      $updatedDoc
    )
    

    性能方面,我认为我的替代品和 Mads Hansen 的替代品具有相同的性能特征。我会说选择你最喜欢的。 我已经将我的方法用于简单的更新用例很多,对于可能还涉及移动节点左右的更复杂的用例,我宁愿使用 Mads Hansen 的 XSLT 替代方案。

    【讨论】:

    • 这个答案基本正确。 xdmp:node-replace() 是一个状态设置函数,它不返回任何内容。所以这个答案相当于let $doc := doc("abc.xml") return xdmp:node-replace($doc//id,&lt;id&gt;1234&lt;/id&gt;),然后在一个新事务中,doc("abc.xml") 来查看更改后的文档
    • @Wargner Michael--谢谢它帮助了我。所以基本上无论我想在任何node operation 期间返回文档结构,那么我都可以返回mem 文档吗?它不会造成性能问题?
    • 我没有看到返回内存文档的问题。这也不应该产生任何性能问题。为您可能想要使用的另一种选择编辑了我的答案。
    • @WagnerMichael 谢谢!这有帮助:)
    【解决方案2】:

    修改内存的另一种方法是通过 XSLT。使用身份转换,创建模板以匹配您要更改的节点:

    xquery version "1.0-ml";
    declare variable $XSLT := 
      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0">
    
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="id/text()">
            <xsl:text>1234</xsl:text>
        </xsl:template>
    
      </xsl:stylesheet>;
    
    let $doc := doc("abc.xml")
    let $modified := xdmp:xslt-eval($XSLT, $doc)
    return 
      ( xdmp:node-replace($doc, $modified), $modified )
    

    【讨论】:

      【解决方案3】:

      可以使用多语句事务using a semi-colon将写事务和读事务分开,这样就可以看到更新了。

      xquery version "1.0-ml";
      xdmp:node-replace(doc("abc.xml")//id, <id>1234</id>)
      ;
      
      xquery version "1.0-ml";
      doc("abc.xml")
      

      【讨论】:

      • 当我尝试使用分号 ; 它给了我 Unxpected Token Syntax Error 并询问 - 你的意思是逗号 ,
      • 不,;。听起来你可能有一个太多的地方。你是在运行我发布的代码,还是申请了另一个可能在某处有额外; 的模块?
      • @Mads-- 我将它应用到我的 XQuery 模块之一,但它没有任何 ;,除了在顶部我声明 variablesimporting 命名空间。
      • 它说我们不能在 XQuery 中使用; 操作符来终止一行
      猜你喜欢
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-09
      • 2011-05-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      相关资源
      最近更新 更多