sanjay
sanjay

Reputation: 1020

XSLT - check node is exist or not using function

I have xml like follows,

<doc>
    <meta-data>
        <paper-name>ABC</paper-name>
        <paper-type>fi</paper-type>
    </meta-data>

    <section>
        <figure>fig1</figure>
        <figure>fig2</figure>
    </section>
</doc>

My requirement is, if <paper-type> node is available in <meta-data> change <figure> nodes to <image> node.

So, output should look like,

<doc>
    <meta-data>
        <paper-name>ABC</paper-name>
        <paper-type>fi</paper-type>
    </meta-data>

    <section>
        <image>fig1</image>
        <image>fig2</image>
    </section>
</doc>

I have written following xsl to do this task,

<xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="abc:check-paper-type" as="xs:boolean">
        <xsl:sequence select="root()//meta-data/paper-type"/>
    </xsl:function>

    <xsl:template match="figure[abc:check-paper-type()]">
        <image>
            <xsl:apply-templates/>
        </image>
    </xsl:template>

to check <paper-type> node is available inside <meta-data> I have written a function here named 'check-paper-type'. but is does not work as expected.

Any suggestion how can I organize my function to check, <paper-type> is available or not?

Note that, I need to change lots of node by checking <paper-type> node exist or not. So, It'll be important to check <paper-type> exist or not by using a function.

Upvotes: 0

Views: 90

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117102

The reason why your attempt cannot work is this:

Within the body of a stylesheet function, the focus is initially undefined; this means that any attempt to reference the context item, context position, or context size is a non-recoverable dynamic error. [XPDY0002]

http://www.w3.org/TR/xslt20/#stylesheet-functions

You could do simply:

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="figure[../../meta-data/paper-type]">
    <image>
        <xsl:apply-templates select="@*|node()"/>
    </image>
</xsl:template>

Given your input, this will produce:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
   <meta-data>
      <paper-name>ABC</paper-name>
      <paper-type>fi</paper-type>
   </meta-data>
   <section>
      <image>fig1</image>
      <image>fig2</image>
   </section>
</doc>

Alternatively, if you need to refer to the existence of the node repeatedly, you can define it as a variable, instead of a function:

<xsl:variable name="check-paper-type" select="exists(/doc/meta-data/paper-type)" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="figure[$check-paper-type]">
    <image>
        <xsl:apply-templates select="@*|node()"/>
    </image>
</xsl:template>

Upvotes: 1

Related Questions