Шаблон вызова XSLT с динамическим QName? - PullRequest
6 голосов
/ 14 апреля 2011

Я искал все вокруг, чтобы найти решение своей проблемы, но у меня просто появилось больше вопросов ...

рассмотрим следующий XML:

<dynamicStuff>
      <dyn id="name1">...</dyn>
      <dyn id="name2">...</dyn>
      <dyn id="name3">...</dyn>
      <dyn id="name4">...</dyn> 
</dynamicStuff>

и предположим, что у меня есть XSLT-файл следующим образом:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

     <xsl:template name="name1">    
         ...
     </xsl:template>

     <xsl:template name="name2">    
         ...
     </xsl:template>

     <xsl:template name="name3">    
         ...
     </xsl:template>

     <xsl:template name="name4">    
         ...
     </xsl:template>

</xsl:stylesheet>

Что я хочу сделать, это из ВТОРОГО файла XSLT динамически определить, какой шаблон вызывать с чем-то вроде этого:

<xsl:variable name="templateName">
     <xsl:value-of select="dyn/@id"/>
</xsl:variable>

<xsl:call-template name="$templateName"/>

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

Я что-то упустил?

Edit:

Я успешно сделал следующее:

<xsl:template name="staticName">
    <xsl:param name="id" />

    <xsl:if test="$id = 'name1'">....</xsl:if>
    <xsl:if test="$id = 'name2'">....</xsl:if>
    ...
</xsl:template>

Вызов таким образом:

<xsl:call-template name="staticName">
     <xsl:with-param name="id" select="@id"/>
</xsl:call-template>

Нужно сказать, насколько это неудобно ... во-первых, мой код будет привязан к этому staticName (представьте, что мне нужно сделать этот вызов в дюжине файлов) ... во-вторых, у меня будет куча (не) связанный контент внутри того же шаблона, когда он может быть более разделен ... кошмар для обновления системы uu

Он делает то, что я хочу, но не так, как мне нужно ...

Заранее спасибо за любой свет по этому вопросу!

Ответы [ 5 ]

6 голосов
/ 14 апреля 2011

С http://www.w3.org/TR/xslt#named-templates

Значением атрибута name является QName , который расширен, как описано в [ 2,4 Квалифицированный Имена ].

Это означает, что это не выражение и не AVT.

Явные xsl:call-template инструкции хороши, будь то логические инструкции или сопоставление с образцом, например:

<xsl:template match="dyn[@id='name1']" mode="dynamic">
 <xsl:call-template name="name1"/>
</xsl:template>

Другой подход называется именованными ссылками на шаблоны ...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="vTemplate" select="document('')/*/xsl:template"/>
    <xsl:template match="dyn">
        <xsl:apply-templates select="$vTemplate[@name = current()/@id]"/>
    </xsl:template>
    <xsl:template match="xsl:template[@name='name1']"
                  name="name1"> one </xsl:template>
    <xsl:template match="xsl:template[@name='name2']"
                  name="name2"> two </xsl:template>
    <xsl:template match="xsl:template[@name='name3']"
                  name="name3"> three </xsl:template>
    <xsl:template match="xsl:template[@name='name4']"
                  name="name4"> four </xsl:template>
</xsl:stylesheet> 

Выход:

 one  two  three  four 


Примечание: Поскольку этот метод использует document('') для обработки XSLT, а не исходного XML-файла, исходный обрабатываемый документ недоступен в названных шаблонах. Однако вы можете явно передать current() в качестве параметра в шаблоны, если это необходимо:
    <xsl:template match="dyn">
        <xsl:apply-templates select="$vTemplate[@name = current()/@id]">
            <xsl:with-param name="current" select="current()"/>
        </xsl:apply-templates>
    </xsl:template>

При необходимости $current может использоваться для доступа к исходному документу:

    <xsl:template match="xsl:template[@name='name1']" name="name1">
        <xsl:param name="current"/>
        <xsl:value-of select="$current/@id"/>
        <xsl:text> becomes one</xsl:text> 
    </xsl:template>

При необходимости $current может быть восстановлено как текущий узел, используя for-each:

<xsl:template match="xsl:template[@name='name2']" name="name2">
    <xsl:param name="current"/>
    <xsl:for-each select="$current">
            <xsl:value-of select="@id"/>
            <xsl:text> becomes two</xsl:text>
    </xsl:for-each>
</xsl:template>
1 голос
/ 04 декабря 2011

Обычно, когда кто-то пытается это сделать, это означает, что он не осознает всю мощь xsl: apply-templates. Способ сделать динамическую отправку в XSLT - использовать xsl: apply-templates. Например, для указанной проблемы напишите правила шаблона, такие как

<xsl:template match="dyn[@id='name1']">...</xsl:template>
<xsl:template match="dyn[@id='name2']">...</xsl:template>
<xsl:template match="dyn[@id='name3']">...</xsl:template>

, а затем используйте <xsl:apply-templates select="dyn"/> для отправки.

1 голос
/ 14 апреля 2011

Если у вас есть только конечное число возможных шаблонов, будет ли работать использование конструкции xsl if для выбора действий в основном шаблоне?

<xsl:if test="$templateName = 'name1'">
  <xsl:call-template name="name1"/>
</xsl:if>
0 голосов
/ 17 января 2013

Если вы используете старый Saxon-B или более новый Saxon-PE или Saxon-EE в качестве процессора XSLT, вы можете использовать расширение saxon для выполнения динамических вызовов шаблонов:

<xsl:variable name="templateName">
     <xsl:value-of select="dyn/@id"/>
</xsl:variable>

<saxon:call-template name="{$templateName}"/>

Не забудьтеобъявить пространство имен саксонии в элементе xsl-stylesheet:

<xsl:stylesheet xmlns:saxon="http://saxon.sf.net/" [...] >
0 голосов
/ 14 апреля 2011

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <t><xsl:apply-templates select="dynamicStuff/dyn"/></t>
    </xsl:template>
    <!-- match on attribute value -->
    <xsl:template match="dyn[@id='name1']">name1</xsl:template>
    <xsl:template match="dyn[@id='name2']">name2</xsl:template>
    <xsl:template match="dyn[@id='name3']">name3</xsl:template>
    <xsl:template match="dyn[@id='name4']">
        <xsl:call-template name="name4"/>
    </xsl:template>
    <!-- named templates -->
    <xsl:template name="name1">name1</xsl:template>
    <xsl:template name="name2">name2</xsl:template>
    <xsl:template name="name3">name3</xsl:template>
    <xsl:template name="name4">name4</xsl:template>
</xsl:stylesheet>

Введите:

<dynamicStuff>
    <dyn id="name1">...</dyn>
    <dyn id="name2">...</dyn>
    <dyn id="name3">...</dyn>
    <dyn id="name4">...</dyn> 
</dynamicStuff>

Выход:

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