Marsoni Nm
Marsoni Nm

Reputation: 47

XSLT Error cause

i've the below xslt.

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="html"/>
    <xsl:template match="/">
        <xsl:text disable-output-escaping="yes">&lt;!DOCTYPE html&gt;</xsl:text>
        <html>
            <head>
                <title>
                    <xsl:value-of select="index/title"/>
                </title>
                <link rel="stylesheet" href="er:#css" type="text/css"/>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
    <xsl:template match="index">
        <div class="index">
            <xsl:variable name="num">
                <xsl:number level="any" format="01"/>
            </xsl:variable>
            <a name="BVI_IDX_{$num}"/>
            <div class="index-title">
                <xsl:apply-templates select="title"/>
                <xsl:value-of select="index/title/@text()"/>
            </div>
            <xsl:apply-templates select="child::node()[not(self::title)]"/>
            <!--<xsl:apply-templates/>-->
        </div>
    </xsl:template>
    <!--<xsl:template match="index">
        <div class="index">
            <div class="index-title">
                <xsl:value-of select="index/title/@text()"/>
            </div>
            <xsl:apply-templates/>
        </div>
    </xsl:template>-->
    <xsl:template match="indexdiv">
        <div class="indexdiv">
            <xsl:apply-templates/>
        </div>
    </xsl:template>
    <xsl:template match="indexdiv/title">

    </xsl:template>
    <xsl:template match="indexentry">
        <div class="indexentry">
            <xsl:apply-templates/>
        </div>
    </xsl:template>
    <xsl:template match="primaryie">
        <div class="primaryie">
            <xsl:apply-templates select="content-style"/>
            <xsl:if test="contains(current()/text(), '.')">
                <xsl:variable name="numberString" select="substring(current()/text(), string-length(substring-before(current()/text(),'.'))-1)"/>
                <xsl:call-template name="numbersToLink">
                    <xsl:with-param name="numbersString" select="$numberString"/>
                </xsl:call-template>
            </xsl:if>
        </div>
    </xsl:template>
    <xsl:template match="secondaryie">
        <xsl:variable name="textAll">
            <xsl:value-of select="text()"/>
        </xsl:variable>
        <xsl:variable name="textOnly">
            <xsl:choose>
                <xsl:when test="contains($textAll,'.')">
                    <xsl:value-of select="substring($textAll,1,string-length(substring-before($textAll,'.'))-1)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="text()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:variable name="textAll1">
            <xsl:value-of select="text()"/>
        </xsl:variable>
        <xsl:variable name="numbersOnly">
            <xsl:choose>
                <xsl:when test="contains($textAll1,'.')">
                    <xsl:value-of select="substring($textAll1,string-length($textOnly))"/>
                </xsl:when>
            </xsl:choose>
        </xsl:variable>
        <div class="secondaryie">
            <xsl:value-of select="$textOnly"/>
            <xsl:call-template name="numbersToLink">
                <xsl:with-param name="numbersString" select="$numbersOnly"/>
            </xsl:call-template>
            <xsl:if test="current()/content-style/node()">
                <xsl:for-each select="current()/content-style">
                    <xsl:call-template name="content-style"/>
                </xsl:for-each>
            </xsl:if>
        </div>
    </xsl:template>
    <xsl:template match="tertiaryie">
        <xsl:variable name="tertClassType">
            <xsl:value-of select="@level"/>
        </xsl:variable>
        <xsl:variable name="tertClassTypName">
            <xsl:value-of select="concat('tertiaryie-', $tertClassType)"/>
        </xsl:variable>
        <xsl:variable name="textAll">
            <xsl:value-of select="text()"/>
        </xsl:variable>
        <xsl:variable name="textOnly">
            <xsl:choose>
                <xsl:when test="contains($textAll,'.')">
                    <xsl:value-of select="substring($textAll,1,string-length(substring-before($textAll,'.'))-1)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="text()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:variable name="textAll1">
            <xsl:value-of select="text()"/>
        </xsl:variable>
        <xsl:variable name="numbersOnly">
            <xsl:choose>
                <xsl:when test="contains($textAll1,'.')">
                    <xsl:value-of select="substring($textAll1,string-length($textOnly))"/>
                </xsl:when>
            </xsl:choose>
        </xsl:variable>
        <div class="{$tertClassTypName}">
            <xsl:value-of select="$textOnly"/>
            <xsl:call-template name="numbersToLink">
                <xsl:with-param name="numbersString" select="$numbersOnly"/>
            </xsl:call-template>
        </div>
    </xsl:template>

    <xsl:template match="content-style" name="content-style">
        <xsl:variable name="fontStyle">
            <xsl:value-of select="concat('font-style-',@font-style)"/>
        </xsl:variable>
        <span class="{$fontStyle}">
            <!--        <xsl:choose>
<xsl:when test="matches(.,".*\d\.\d+-\d\.\d+.*")">
</xsl:when>
        </xsl:choose>
-->
<xsl:variable name="textAll">
                <xsl:value-of select="../text()"/>
            </xsl:variable>
            <xsl:choose>
                <xsl:when test="contains($textAll, '.')">

            <xsl:variable name="textOnly">
                <xsl:choose>
                    <xsl:when test="contains($textAll,'.')">
                        <xsl:value-of select="substring($textAll,1,string-length(substring-before($textAll,'.'))-1)"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="text()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:variable name="numbersOnly">
                <xsl:choose>
                    <xsl:when test="contains($textAll,'.')">
                        <xsl:value-of select="substring($textAll,string-length($textOnly))"/>
                    </xsl:when>
                </xsl:choose>
            </xsl:variable>
                            <xsl:value-of select="$textOnly"/>
                <xsl:call-template name="numbersToLink">
                    <xsl:with-param name="numbersString" select="$numbersOnly"/>
                </xsl:call-template>

                </xsl:when>

            <xsl:otherwise>
                         <xsl:apply-templates/>
            </xsl:otherwise>
            </xsl:choose>


        </span>
    </xsl:template>

    <xsl:template name="numbersToLink">
        <xsl:param name="numbersString"/>
        <xsl:choose>
            <xsl:when test="contains($numbersString, ',')">
                <xsl:call-template name="splitByComma">
                    <xsl:with-param name="numString" select="$numbersString"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains($numbersString, '-')">
                <xsl:call-template name="splitByHyphen">
                    <xsl:with-param name="numString" select="$numbersString"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="5 >= string-length(normalize-space($numbersString))">
                <xsl:variable name="x">
                    <xsl:value-of select="substring-after($numbersString,'.')"/>
                </xsl:variable>
                <xsl:variable name="y">
                    <xsl:value-of select="normalize-space(substring-before($numbersString,'.'))"/>
                </xsl:variable>
                <!--  er:#BVI_CH_07/P7-251-->
                <xsl:variable name="conca">
                    <xsl:value-of select="concat('er:#BVI_CH_0',$y,'/P',$y,'-',$x)"/>
                </xsl:variable>
                <a href="{$conca}">
                    <xsl:value-of select="$numbersString"/>
                </a>
            </xsl:when>
            <xsl:otherwise>

            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="splitByComma">
        <xsl:param name="numString"/>
        <xsl:choose>
            <xsl:when test="contains(substring-before($numString,','), '-')">
                <xsl:call-template name="splitByHyphen">
                    <xsl:with-param name="numString" select="$numString"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains($numString,',')">
                <xsl:variable name="abc">
                    <xsl:value-of select="normalize-space(substring-before($numString,'.'))"/>
                </xsl:variable>
                <xsl:variable name="def">
                    <xsl:value-of select="substring-before(substring-after($numString,'.'),',') "/>
                </xsl:variable>
                <xsl:variable name="conct">
                    <xsl:value-of select="concat('er:#BVI_CH_0',$abc,'/P',$abc,'-',$def)"/>
                    <!--"concat(concat('er:#BVI_CH_0',,'/P',$y,'-',$x)"/-->
                </xsl:variable>
                <a href="{$conct}">
                    <xsl:value-of select="substring-before($numString,',')"/>
                </a>
                <xsl:text>, </xsl:text>
                <xsl:if test="contains(substring-after($numString,','), '.')">
                    <xsl:call-template name="numbersToLink">
                        <xsl:with-param name="numbersString" select="normalize-space(substring-after($numString,','))"/>
                    </xsl:call-template>
                </xsl:if>
            </xsl:when>
        </xsl:choose>
    </xsl:template>
    <xsl:template name="splitByHyphen">
        <xsl:param name="numString"/>
        <xsl:choose>
            <xsl:when test="contains($numString,'-')">
                <xsl:variable name="abc">
                    <xsl:value-of select="normalize-space(substring-before($numString,'.'))"/>
                </xsl:variable>
                <xsl:variable name="def">
                    <xsl:value-of select="substring-before(substring-after($numString,'.'),'-') "/>
                </xsl:variable>
                <xsl:variable name="conct">
                    <xsl:value-of select="concat('er:#BVI_CH_0',$abc,'/P',$abc,'-',$def)"/>
                    <!--"concat(concat('er:#BVI_CH_0',,'/P',$y,'-',$x)"/-->
                </xsl:variable>
                <a href="{$conct}">
                    <!--<xsl:value-of select="substring-before($numString,'-')"/>-->
                    <xsl:value-of select="substring-before($numString,'-')"/>
                </a>
                <xsl:text>&#x2013;</xsl:text>
                <xsl:if test="contains(substring-after($numString,'-'), '.')">
                    <xsl:call-template name="numbersToLink">
                        <xsl:with-param name="numbersString" select="normalize-space(substring-after($numString,'-'))"/>
                    </xsl:call-template>
                </xsl:if>
            </xsl:when>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

When i'm using this with my xml sheet in Altova XMLSpy. it is not giving any error. but when i'm using with other xml editors(oxygen and liquid xml) it is throwing the below error.

    Severity: error
Description: A sequence of more than one item is not allowed as the first argument of contains() ("", "") 
Start location: 56:0
URL: http://www.w3.org/TR/xpath20/#ERRXPTY0004

please let me know why is this happening and how do i fix it?

Thanks.

Upvotes: 0

Views: 2575

Answers (2)

Michael Kay
Michael Kay

Reputation: 163342

Line 56 is this:

The error means that the current node (a primaryie element) has more than one text node child. Perhaps some of these are whitespace text nodes - Altova uses the Microsoft XML parser, which strips whitespace text nodes by default. It's hard to know what you should replace this with, without knowing your application, but it should perhaps be test="contains(., '.')".

Incidentally, there's some bad code in your stylesheet. This:

<xsl:value-of select="index/title/@text()"/>

selects all the text nodes on the attribute axis. There will never be any text nodes on the attribute axis, though it's legal to ask for them. Your stylesheet also makes frequent use of the construct

<xsl:variable name="tertClassType">
     <xsl:value-of select="@level"/>
</xsl:variable>

which is a terribly inefficient and verbose way of getting the same effect as

<xsl:variable name="tertClassType" select="@level"/>

Upvotes: 3

Martin Honnen
Martin Honnen

Reputation: 167571

Which line exactly causes that error? And how does the XML input look?

Altova is known to strip white space text nodes, if you want the same behavior with Saxon then add

<xsl:strip-space elements="*"/>

as a child of the xsl:stylesheet element. That might fix it, assuming that the error is caused by an attempt to select text contents with text() which then includes white space text nodes with Saxon which are stripped with Altova.

But generally I would avoid using text() and simply select the string contents with . (and relying on atomization of the function argument when passed to functions like contains) or do string(.) explicitly.

Upvotes: 4

Related Questions