【问题标题】:Call XSLT Function from a XSLT template从 XSLT 模板调用 XSLT 函数
【发布时间】:2019-05-06 13:43:38
【问题描述】:

我有以下示例 xml 输入。

<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>

我想生成以下响应消息。

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

为此,我尝试使用以下 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>

当时我收到以下错误消息。 无法使用提供的 XML/XSL 输入生成 XML 文档。 '/'的第一个操作数的必需项类型是node();提供的值具有项目类型 xs:string

我对 XSLT 不太熟悉。你对这个问题有什么想法吗?

【问题讨论】:

  • &lt;xsl:when test="$givenDate/text() !=''"&gt; 更改为&lt;xsl:when test="$givenDate !=''"&gt;。传递给函数的 $givenDate 是一个 xs:string 变量,因此您不能/不需要获取它的 text() 值。
  • 您的样式表显示version="1.0"xsl:function 指令是 XSLT 2.0 的一个特性。
  • @zx485 - 感谢您的建议。这是工作。现在没有错误消息。但是预期的消息没有按预期出现。输出 - {"abc": "}
  • @KittyKotte:输出错误,因为您没有修复样式表的版本。因此,将version="1.0" 更改为version="2.0",代码将按预期工作。

标签: xml xslt


【解决方案1】:

无法使用提供的 XML/XSL 输入生成 XML 文档。 '/'的第一个操作数的必需项类型是node();提供 值具有项目类型 xs:string

[...] 你对这个问题有什么想法吗?

该消息表示步进路径运算符/ 的左侧参数必须为节点类型。因为您已将$givenDate 声明为substring-before(...),所以它将是xs:string 类型。因此,当您在表达式$givenDate/text() 中使用它时出现错误,正如zx485 comment 已经指出的那样

我认为最好在函数本身中执行从 xs:dateTime 到 xs:date 或 'null' 的转换,就像在这个 XSLT 2.0 样式表中一样:

<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>

输出:

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

请注意:如果您有 dateTime 数据,则转换将保留时区信息。

【讨论】:

  • 谢谢@Alejandro。但我需要使用 XSLT 1.0 样式表。
  • @KittyKotte 您的错误消息来自 XSLT 2.0 处理器,xsl:function 元素是 XSLT 2.0 功能。你说in comments 你的样式表“有效”那是因为您使用的是 XSLT 2.0 处理器
【解决方案2】:

我认为您已经找到了错误,但错误的根本原因(或您解决它的困难)是未能声明变量和参数的类型。如果您遵循函数的参数和结果应始终具有声明类型的规则,那么您会问自己函数接受什么样的值以及返回什么,您可能会决定输入和输出都是字符串,导致声明:

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

有了这些声明,编译器就可以直接告诉你哪里出了问题。 $givenDate/text() 没有意义,因为字符串没有子文本节点;和返回值

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

没有意义,因为文本节点序列无法转换为字符串。返回字符串结果最简单最直接的方式大概是

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

虽然如果您想避免使用转义引号,那么另一种选择是很少见

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

将三个文本节点合二为一(类型声明 as="xs:string" 然后导致文本节点隐式转换为字符串。您也可以将其缩写为

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

或者在 XSLT 3.0 中,使用 expand-text="yes" 您可以使用文本值模板:

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

【讨论】:

    【解决方案3】:

    试了几次,问题就解决了。

    <?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>
    

    【讨论】:

      猜你喜欢
      • 2017-06-29
      • 2016-11-26
      • 1970-01-01
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多