Re: [xsl] A use-case for xsl:merge?

Subject: Re: [xsl] A use-case for xsl:merge?
From: "Martin Honnen martin.honnen@xxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 15 Feb 2019 20:21:07 -0000
On 15.02.2019 21:01, John Dziurlaj john@xxxxxxxxxxxxxxxx wrote:
The element prototypes can be in the same document or different documents,
but for the purposes of the XSLT3 we are only concerned with merging the
external references, such that we have a fully dereferenced (i.e.
standalone) XML instance.

I already have code to pull in the external references (prototypes) and run
the XPath (via evaluate) on them. I've put all the code on GitHub to
hopefully make this easier to understand.

I am not sure I understand all that sample code, there are two XML documents, one seems incomplete.


I am not sure it is a use case for xsl:merge (order their matters and I am not sure about the order of your items to be merged), I think it can be done with recursive templates using `for-each-group`:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
    xmlns:xs="http://www.w3.org/2001/XMLSchema";
    xmlns:math="http://www.w3.org/2005/xpath-functions/math";
    exclude-result-prefixes="xs math"
    version="3.0">

<xsl:param name="prot-doc-uri" as="xs:string">prototype.xml</xsl:param>

<xsl:param name="prot-doc" select="doc($prot-doc-uri)"/>

<xsl:mode on-no-match="shallow-copy"/>

<xsl:output indent="yes"/>

    <xsl:template match="*[@usehref]">
        <xsl:copy>
            <xsl:variable name="prototype" as="element()?">
                <xsl:evaluate xpath="@usehref" context-item="$prot-doc"/>
            </xsl:variable>
            <xsl:apply-templates select="." mode="merge-attributes">
                <xsl:with-param name="prototype" select="$prototype"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="." mode="merge-children">
                <xsl:with-param name="prototype" select="$prototype"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

<xsl:template match="*" mode="merge-attributes">
<xsl:param name="prototype"/>
<xsl:for-each-group select="@* except @usehref, $prototype/(@* except @name)" group-by="node-name()">
<xsl:sequence select="."/>
</xsl:for-each-group>
</xsl:template>


<xsl:template match="*" mode="merge-children">
<xsl:param name="prototype"/>
<xsl:for-each-group select="*, $prototype/*" group-by="node-name()">
<xsl:copy>
<xsl:apply-templates select="." mode="merge-attributes">
<xsl:with-param name="prototype" select="current-group()[2]"/>
</xsl:apply-templates>
<xsl:apply-templates select="." mode="merge-children">
<xsl:with-param name="prototype" select="current-group()[2]"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:for-each-group>
</xsl:template>


</xsl:stylesheet>


That assumes the first input is e.g. (note that I had to adjust the XPath expression to use "@name" instead of "name")


<root>
    <draw name="Text1" usehref="/proto/draw[@name = 'TextStyle1']">

<ui>

<textEdit/>

</ui>

<value>

<text>This is some text</text>

</value>

<border/>

<font weight="bold"/>

    </draw>
</root>


and the referenced file has e.g.


<proto>
    <draw name="TextStyle1" w="29.2864mm" h="5.2331mm">

<ui>

<textEdit/>

</ui>

<border>

<edge presence="hidden"/>

</border>

<font size="12pt" typeface="Myriad Pro"/>

<margin topInset="0.5mm" bottomInset="0.5mm" leftInset="0.5mm" rightInset="0.5mm"/>

    </draw>
</proto>

then the result is

<root>
    <draw name="Text1" w="29.2864mm" h="5.2331mm">
      <ui>
         <textEdit/>
      </ui>
      <value>
         <text/>
      </value>
      <border>
         <edge presence="hidden"/>
      </border>
      <font weight="bold" size="12pt" typeface="Myriad Pro"/>
      <margin topInset="0.5mm"
              bottomInset="0.5mm"
              leftInset="0.5mm"
              rightInset="0.5mm"/>
   </draw>
</root>

Current Thread