简体   繁体   中英

Call XSLT Function from a XSLT template

I have the following sample xml input.

<RootElement xmlns="http://example.com">
<aa>test</aa>
<bb>ffff</bb>
<cc>dere</cc>
<givenDate>2016-07-23T00:00:00.000+00:00</givenDate>
</RootElement>

I want to generate the following response message.

{
"abc" : "2016-07-23"
}

For that I tried to use the following xslt.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="http://example.com" version="1.0" exclude-result-prefixes="ns">
    <xsl:output method="text" omit-xml-declaration="yes" indent="no" encoding="UTF-8" media-type="application/json"/>
    <xsl:template match="/">
        <xsl:text>{</xsl:text>

        <xsl:text>"abc": </xsl:text>
        <xsl:variable name="givenDate" select="substring-before(//ns:RootElement/ns:givenDate, 'T')"/>
        <xsl:value-of select="ns:set_value($givenDate)"/>

        <xsl:text>}</xsl:text>
    </xsl:template> 

    <xsl:function name="ns:set_value">
        <xsl:param name="givenDate"/>
        <xsl:choose>
            <xsl:when test="$givenDate/text() !=''">
                <xsl:text>"</xsl:text><xsl:value-of select="$givenDate"/><xsl:text>"</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>null</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>

</xsl:stylesheet>

At that time I'm getting below error message. Unable to generate the XML document using the provided XML/XSL input. Required item type of first operand of '/' is node(); supplied value has item type xs:string

I'm not much familiar with XSLT. Do you have any idea about the issue?

Unable to generate the XML document using the provided XML/XSL input. Required item type of first operand of '/' is node(); supplied value has item type xs:string

[...] Do you have any idea about the issue?

The message means that left hand argument for step path operator / must be of node type. Because you have declared $givenDate as substring-before(...) , it would be of type xs:string . Thus the error when you use it in the expression $givenDate/text() , as already pointed by zx485 comment

I think that it would be better to perform such conversion from xs:dateTime to xs:date or 'null' in the function itself like in this XSLT 2.0 stylesheet:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns="http://example.com" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="ns xs">
    <xsl:output method="text" omit-xml-declaration="yes"/>
    <xsl:template match="/">
        <xsl:text>{&#xA;"abc": </xsl:text>
        <xsl:value-of select="ns:set_value(//ns:RootElement/ns:givenDate)"/>
        <xsl:text>&#xA;}</xsl:text>
    </xsl:template> 

    <xsl:function name="ns:set_value">
        <xsl:param name="givenDate"/>
        <xsl:sequence 
            select="if ($givenDate castable as xs:dateTime)
                    then xs:date(xs:dateTime($givenDate))
                    else 'null'"/>
    </xsl:function>
</xsl:stylesheet>

Output:

{
"abc": 2016-07-23Z
}

Do note: if you have a dateTime data, the casting wiil retain timezone information.

I think you've found the error, but the root cause of the error (or of your difficulty in solving it) is the failure to declare the types of your variables and parameters. If you followed the rule that parameters and results of functions should always have a declared type, then you would have asked yourself what kind of value the function accepts and what it returns, and you would probably have decided that the input and output are both strings, leading to the declaration:

<xsl:function name="ns:set_value" as="xs:string">
   <xsl:param name="givenDate" as="xs:string"/>

With these declarations, the compiler would be able to tell you directly what is wrong. $givenDate/text() doesn't make sense because a string doesn't have child text nodes; and the return value

<xsl:text>"</xsl:text>
<xsl:value-of select="$givenDate"/>
<xsl:text>"</xsl:text>

doesn't make sense because a sequence of text nodes can't be converted to a string. The simplest and most direct way to return the string result is probably

<xsl:sequence select='concat("""", $givenDate, """")'/>       

though if you want to avoid messing about with escaped quotes then an alternative would be the rarely-seen

<xsl:value-of>
    <xsl:text>"</xsl:text>
    <xsl:value-of select="$givenDate"/>
    <xsl:text>"</xsl:text>
</xsl:value-of>

which combines three text nodes into one (and the type declaration as="xs:string" then causes implicit conversion of the text node to a string. You could also abbreviate this to

<xsl:value-of>"<xsl:value-of select="$givenDate"/>"</xsl:value-of>

Or in XSLT 3.0, with expand-text="yes" you could use a text value template:

<xsl:value-of>"{$givenDate}"</xsl:value-of>          

After trying several time, I could resolve the issue.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="http://example.com" version="1.0" exclude-result-prefixes="ns"  xmlns:func="http://exslt.org/functions">
    <xsl:output method="text" omit-xml-declaration="yes" indent="no" encoding="UTF-8" media-type="application/json"/>
    <xsl:template match="/">
        <xsl:text>{</xsl:text>
        <xsl:text>"abc": </xsl:text>
        <xsl:variable name="givenDate" select="substring-before(//ns:RootElement/ns:givenDate, 'T')"/>

        <xsl:value-of select="ns:set_value($givenDate)"/>

        <xsl:text>}</xsl:text>
    </xsl:template> 

    <xsl:function name="ns:set_value">
        <xsl:param name="givenDate"/>
        <xsl:choose>
            <xsl:when test="$givenDate !=''">
 <func:result>
<xsl:text>"</xsl:text>
                <xsl:value-of select="$givenDate"/>
<xsl:text>"</xsl:text>
 </func:result>
            </xsl:when>
            <xsl:otherwise>
                <xsl:text>null</xsl:text>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>

</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM