How to update a node/element in xquery marklogic

Viewed 193

How can we update a value in xquery other than node-replace? I have an element called title which is empty , I should be updating the value as “submitted”. Sample file:

<books>
<title></title>
</books>
1 Answers

I assume you are asking for an alternative to xdmp:node-replace() because this XML doc is an in-memory object and not (yet) a persisted document?

You could perform a recursive descent typeswitch

xquery version "1.0-ml";

(: This is the recursive typeswitch function :)
declare function local:transform($nodes as node()*) as node()*
{
for $n in $nodes return
typeswitch ($n)
  case text() return $n
  case attribute() return $n
  case comment() return $n 
  case processing-instruction() return $n
  case element (title) return <title>submitted</title>
  default return element {$n/name()} {local:transform($n/(@*|node()))}
};

let $books :=
   <books foo="x"><!--test--><?PITarget PIContent?>
    <title></title>
  </books>
return
  local:transform($books)

, but I find that to be tedious and don't like for general purpose transformations if you wind up needing more complex transformation scenarios.

For more complicated transformations of in-memory XML structures in XQuery, then I would look to use Ryan Dew's XQuery XML Memory Operations library:

import module namespace mem = "http://maxdewpoint.blogspot.com/memory-operations" 
  at "/memory-operations.xqy";

let $books :=
   <books>
    <title></title>
  </books>
return 
  mem:copy(fn:root($books)) ! (
    mem:replace(., $books/title, element title {"submitted"}),
    mem:execute(.)
  )

When transforming XML (whether in-memory or documents in the database), I prefer XSLT. You could use either xdmp:xslt-invoke() (with an installed stylesheet) or with xdmp:xslt-eval():

xquery version "1.0-ml";
let $xslt :=
  <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:template>
    
    <xsl:template match="title">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:text>submitted</xsl:text>
        </xsl:copy>
    </xsl:template>
    
  </xsl:stylesheet>

let $books := 
  <books>
    <title></title>
  </books>

return xdmp:xslt-eval($xslt, $books)
Related