I want to Wrap multiple nodes (specific nodes) into a new single node within my xml document and then want to insert it.
Example XML Document-
<root>
<value1>somevalue</value1>
<value2>somevalue</value2>
<value3>somevalue</value3>
<value4>somevalue</value4>
<value5>Australia</value5>
<value6>India</value6>
<value7>USA</value7>
<value8>somevalue</value8>
<value9>somevalue</value9>
<value10>somevalue</value10>
</root>
Since my value5 to value7 are name of the countries, i want to put them at the same father node. The output need to look like this:
Output-
<root>
<value1>somevalue</value1>
<value2>somevalue</value2>
<value3>somevalue</value3>
<value4>somevalue</value4>
<Country>
<value5>Australia</value5>
<value6>India</value6>
<value7>USA</value7>
</Country>
<value8>somevalue</value8>
<value9>somevalue</value9>
<value10>somevalue</value10>
</root>
Similarly if my other values belong to some other fields/properties then i want to WRAP them in a new single node.
Any Suggestions?
You could achieve what you are trying to do in XSLT, using xsl:for-each-group
.
If you want to group them when the value is not equal to "somevalue", then you could use group-adjacent
to test whether the element value is equal to "somevalue" or not, and then wrap those that are not in the <country>
element.
You can execute an XSLT within your XQuery module in MarkLogic, like this:
xquery version "1.0-ml";
declare variable $doc := document {
<root>
<value1>somevalue</value1>
<value2>somevalue</value2>
<value3>somevalue</value3>
<value4>somevalue</value4>
<value5>Australia</value5>
<value6>India</value6>
<value7>USA</value7>
<value8>somevalue</value8>
<value9>somevalue</value9>
<value10>somevalue</value10>
</root>
};
declare variable $grouping-xslt :=
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" group-adjacent=". = 'somevalue'">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:copy-of select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<country>
<xsl:copy-of select="current-group()"/>
</country>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>;
xdmp:xslt-eval($grouping-xslt, $doc)
If you have a known sequence of country names that you would want to group by, then you could do that with group-by
and test whether the value matches any of the country names:
xquery version "1.0-ml";
declare variable $doc := document {
<root>
<value1>somevalue</value1>
<value2>somevalue</value2>
<value3>somevalue</value3>
<value4>somevalue</value4>
<value5>Australia</value5>
<value6>India</value6>
<value7>USA</value7>
<value8>somevalue</value8>
<value9>somevalue</value9>
<value10>somevalue</value10>
</root>
};
declare variable $grouping-xslt :=
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:param name="countries" />
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" group-by=". = $countries">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<country>
<xsl:copy-of select="current-group()"/>
</country>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>;
declare variable $params := map:new(map:entry("countries", ("Australia", "India", "USA")));
xdmp:xslt-eval($grouping-xslt, $doc, $params)