Search code examples
xmlcomparexsl-fosaxon

how to compare xpath to current node


I am using saxon to convert xml to xsl-fo. Each file has a companion file that contains xpaths to the elements that have changed. I need to compare the xpath in the companion file against the current node. For example if the current node being processed is item8 then according to the companion file it should get a change bar:

xml file

<body>
    <unlist bulltype="NDASH" code="00019292.0001001.007" layer="1" lid="N.00019292.0001001.014">
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.015">item1</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.018">item2</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.019">item3</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.020">item4</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.021">item5</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.022">item6</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.023">item7</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.024">item8</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.025">item9</para>
        </item>
        <item layer="1">
            <para layer="1" lid="N.00019292.0001001.026">item10</para>
        </item>
    </unlist>
</body>

companion file

<rev-marks>
    <rev anchor="false" chg="R" origin="airbus"
      path="//*[@lid='N.00019292.0001001.014']/item[9]/para[1]"/>
    <rev anchor="false" chg="R" origin="airbus"
      path="//*[@lid='N.00019292.0001001.014']/item[8]/para[1]">
      <hl-ref ref="hl_1"/>
    </rev>
    <rev anchor="true" chg="R" origin="airbus" path="//*[@lid='N.00019292.0001001.014']"/>
  </rev-marks>

Essentially I need to put an fo change bar if the current node's path matches the rev/@path in the companion file. Any help would be appreciated.

Edited to show what i have so far

<xsl:template match="para">
<!-- path of the current node -->
<xsl:variable name="curPath" select="saxon:path()"/> 
<!-- path of the companion file --> 
<xsl:variable name="mdata">../MU/<xsl:value-of select="ancestor::description/@code"/>_mdata.xml</xsl:variable>
        
<xsl:for-each select="document($mdata,.)//rev">
    <!-- value of //rev/@path in the companion file -->
    <xsl:variable name="revPath" select="@path"/>
                
    <xsl:if test="$revPath = $curPath">
        <fo:change-bar-begin change-bar-class="cbpara" change-bar-color="black" change-bar-style="solid" change-bar-offset="15pt"/>
    </xsl:if>
            
</xsl:for-each>
<fo:block>
    <xsl:apply-templates/>
</fo:block>
<!-- add fo:change-bar-end here -->
</xsl:template>

It is this statement that i cannot get a comparison of the 2 xpath expressions <xsl:if test="$revPath = $curPath">

Hope this clarifies


Solution

  • An example of using xsl:evaluate (supported in Saxon 9.8 and later of the PE and EE editions, in Saxon 10 all editions and in Saxon-JS 2) is:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:mf="http://example.com/mf"
        exclude-result-prefixes="#all"
        version="3.0">
        
        <xsl:param name="rev-doc-uri" as="xs:string">evaluate-key-ref-marks.xml</xsl:param>
        
        <xsl:param name="rev-doc" select="doc($rev-doc-uri)"/>
        
        <xsl:function name="mf:select-node" as="node()*">
            <xsl:param name="path" as="xs:string"/>
            <xsl:param name="context-doc" as="node()"/>
            <xsl:evaluate context-item="$context-doc" xpath="$path"/>
        </xsl:function>
        
        <xsl:mode on-no-match="shallow-copy"/>
        
        <xsl:template match="*[some $rev in $rev-doc//rev[@path] satisfies (. is mf:select-node($rev/@path, /))]">
            <xsl:comment>marked</xsl:comment>
            <xsl:next-match/>
        </xsl:template>
        
    </xsl:stylesheet>
    

    Online sample using Saxon-JS 2 in the browser (second XML is inlined there for self-completeness of the example).