Построение переменной с шаблоном в XSLT и затем применение xpath

#xpath #xslt-2.0

#xpath #xslt-2.0

Вопрос:

Я использую следующий xslt

 <xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.test.com/services/test/test/v1">

    <xsl:output method="xml" encoding="UTF-8"
        omit-xml-declaration="yes" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="/">

            <xsl:variable name="mytree">
                <xsl:call-template name="myvariable">
                </xsl:call-template>
            </xsl:variable>

        <xsl:choose>    
            <xsl:when test="count($mytree/foos/foo) amp;> 1">
                <xsl:copy-of select="$mytree"/>
            </xsl:when>
            <xsl:otherwise>
                <error>test</error>
            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>

    <xsl:template name="myvariable">
        <foos>
            <foo>bar1</foo>
            <foo>bar2</foo>
            <foo>bar3</foo>
            <foo>bar4</foo>
        </foos>
    </xsl:template>   

</xsl:stylesheet>
  

Когда я использую приведенный выше xslt, должен быть следующий вывод

 <foos xmlns="http://www.test.com/services/test/test/v1">
    <foo>bar1</foo>
    <foo>bar2</foo>
    <foo>bar3</foo>
    <foo>bar4</foo>
</foos>
  

но это

 <error xmlns="http://www.test.com/services/test/test/v1">test</error>
  

когда я удаляю xmlns="http://www.test.com/services/test/test/v1" вывод правильный. Не уверен, что происходит?

Ответ №1:

Что ж, с любым XML, будь то созданный внутри вашего XSLT или прочитанный из источника, если у вас есть элементы в определенном пространстве имен, тогда, чтобы выбрать их с помощью XPath в XSLT, в XSLT 2 у вас есть два варианта, либо использовать xpath-default-namespace="http://www.test.com/services/test/test/v1" (например <xsl:when test="count($mytree/foos/foo) amp;> 1" xpath-default-namespace="http://www.test.com/services/test/test/v1"> ), либо привязать пространство имен к префиксу (например <xsl:when xmlns:v1="http://www.test.com/services/test/test/v1" test="count($mytree/v1:foos/v1:foo) amp;> 1"> ).

Вы можете использовать эти подходы для элемента-предка, например, корневого элемента таблицы стилей, если это не мешает другим выборкам, которые вы хотите сделать.

Комментарии:

1. спасибо, наконец-то я попробовал с <xsl:when test=»count($mytree/*:foos/*:foo) > 1″>

Ответ №2:

Вы должны указать полные имена элементов в вашем выражении XPath для обращения к элементам foos и foo в вашем пространстве имен по умолчанию http://www.test.com/services/test/test/v1 :

  • Зарегистрируйте пространство имен по умолчанию еще раз с префиксом пространства имен (например, myns ): xmlns:myns="http://www.test.com/services/test/test/v1"
  • Используйте этот префикс пространства имен в ваших выражениях XPath для обращения к узлам в этом пространстве имен (например, myns:foos/myns:foo ).
  • Добавьте, exclude-result-prefixes="myns" чтобы подавить myns префикс в вашем результирующем документе.
 <xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.test.com/services/test/test/v1"

    xmlns:myns="http://www.test.com/services/test/test/v1"
    exclude-result-prefixes="myns"><xsl:template match="/"><xsl:choose>
            <xsl:when test="count($mytree/myns:foos/myns:foo) amp;> 1">
                <xsl:copy-of select="$mytree"/>
            </xsl:when>
            <xsl:otherwise>
                <error>test</error>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template></xsl:stylesheet>
  

смотрите Скрипту XSLT


Если бы у вас был только процессор XSLT 1.0, вам понадобилась бы функция node-set EXSLT для доступа к $mytree переменным из дерева результатов:

 <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.test.com/services/test/test/v1"

    xmlns:exsl="http://exslt.org/common"
    extension-element-prefixes="exsl"
    xmlns:myns="http://www.test.com/services/test/test/v1"
    exclude-result-prefixes="myns"><xsl:template match="/"><xsl:choose>
            <xsl:when test="count(exsl:node-set($mytree)/myns:foos/myns:foo) amp;> 1">
              <xsl:copy-of select="$mytree"/>
            </xsl:when>
            <xsl:otherwise>
                <error>test</error>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template></xsl:stylesheet>
  

Ответ №3:

Используйте код для удаления пространства имен

 <xsl:template match="@*[namespace-uri() = 'http://www.test.com/services/test/test/v1']"/>