Вызов функции XSLT из шаблона XSLT - PullRequest
0 голосов
/ 06 мая 2019

У меня есть следующий пример ввода 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 с использованием предоставленного ввода XML / XSL.Обязательный тип элемента первого операнда '/' - это node ();предоставленное значение имеет тип элемента xs: string

Я не очень знаком с XSLT.Есть ли у вас какие-либо идеи по поводу проблемы?

Ответы [ 3 ]

0 голосов
/ 06 мая 2019

После нескольких попыток я смог решить проблему.

<?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>
0 голосов
/ 06 мая 2019

Я думаю, что вы нашли ошибку, но основной причиной ошибки (или вашей трудности в ее решении) является неспособность объявить типы ваших переменных и параметров. Если бы вы следовали правилу, согласно которому параметры и результаты функций всегда должны иметь объявленный тип, то вы бы спросили себя, какое значение принимает функция и что она возвращает, и вы, вероятно, решили бы, что оба ввода и вывода являются строками , ведущий к объявлению:

<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: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>
0 голосов
/ 06 мая 2019

Невозможно сгенерировать документ XML с использованием предоставленного ввода XML / XSL. Обязательный тип элемента первого операнда '/' - это 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, при кастинге будет сохранена информация о часовом поясе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...