Как вызвать именованный шаблон xslt на определенном узле

#xml #xslt

#xml #xslt

Вопрос:

У меня очень однородный входной XML, который мне нужно преобразовать в совершенно настраиваемый XML. Для этого я пытаюсь вызвать шаблоны имен в разных местах XSL. Моя проблема заключается в том, что невозможно выбрать узел при вызове шаблона, что приводит к очень длинному и избыточному коду, такому как этот (упрощенный пример для иллюстрации проблемы):

 <xsl:template match="/">

    <workspace>
       <data>
            <xsl:apply-templates select="/data/data_set[@id='id1']" />                  
            <xsl:apply-templates select="/data/data_set[@id='id2']" />                  
            <xsl:apply-templates select="/data/data_set[@id='id3']" />                  
       </data>
    </workspace>

</xsl:template>


<xsl:template match="/data/data_set[@id='id1']">            
    <xsl:call-template name="attribute">                            
        <xsl:with-param name="id" select="'some_value1'" />
        <xsl:with-param name="type" select="'some_value2'" />
    </xsl:call-template>
</xsl:template>

<xsl:template match="/data/data_set[@id='id2']">            
    <xsl:call-template name="attribute">                            
        <xsl:with-param name="id" select="'some_other_value1'" />
        <xsl:with-param name="type" select="'some_other_value2'" />
    </xsl:call-template>
</xsl:template>

<xsl:template match="/data/data_set[@id='id3']">            
    <xsl:call-template name="attribute">                            
        <xsl:with-param name="id" select="'some_third_value1'" />
        <xsl:with-param name="type" select="'some_third_value2'" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="attribute">
    <xsl:param name="id" />
    <xsl:param name="type" />       

     <!-- Write the attribute node -->
    <attribute attribute_id="{$id}" attribute_value_type="{$type}">         
        <xsl:for-each select="data_point">
            <element>
                <xsl:attribute name="id"><xsl:value-of select="@key" /></xsl:attribute>
                <xsl:attribute name="{$type}"><xsl:value-of select="@value" /></xsl:attribute>                                          
            </element>
        </xsl:for-each>
    </attribute>            

</xsl:template>
  

Есть ли лучший способ сделать это, чтобы избежать всей этой избыточности? Я бы хотел написать что-то вроде этого (но это недопустимый XSLT), поскольку вы не можете выполнить выбор в шаблоне вызова.

 <xsl:template match="/">
    <workspace>
       <data>
        <xsl:call-template name="attribute" select="/data/data_set[@id='id1']">                         
            <xsl:with-param name="id" select="'some_value1'" />
            <xsl:with-param name="type" select="'some_value2'" />
        </xsl:call-template>
        <xsl:call-template name="attribute" select="/data/data_set[@id='id2']">                         
            <xsl:with-param name="id" select="'some_other_value1'" />
            <xsl:with-param name="type" select="'some_other_value2'" />
        </xsl:call-template>
        <xsl:call-template name="attribute" select="/data/data_set[@id='id3']">                         
            <xsl:with-param name="id" select="'some_third_value1'" />
            <xsl:with-param name="type" select="'some_thrid_value2'" />
        </xsl:call-template>           
       </data>
    </workspace>
</xsl:template>
  

Пример ввода:

 <?xml version="1.0" encoding="utf-8"?>
<data>
      <data_set id="id1">
         <data_point value="1" key="4"/>
         <data_point value="2" key="5"/>
         <data_point value="3" key="6"/>
      </data_set>
      <data_set id="id2">
         <data_point value="1" key="4"/>
         <data_point value="2" key="5"/>
         <data_point value="3" key="6"/>
      </data_set>
      <data_set id="id3">
         <data_point value="1" key="4"/>
         <data_point value="2" key="5"/>
         <data_point value="3" key="6"/>
      </data_set>
</data>
  

Пример вывода:

 <?xml version="1.0" encoding="utf-8"?>
<workspace>
    <data>
        <attribute id="some_value1" type="some_value2">
            <element id="4" some_value2="1"/>
            <element id="5" some_value2="2"/>
            <element id="6" some_value2="3"/>
        </attribute>
        <attribute id="some_other_value1" type="some_other_value2">
            <element id="4" some_other_value2="1"/>
            <element id="5" some_other_value2="2"/>
            <element id="6" some_other_value2="3"/>
        </attribute>
        <attribute id="some_third_value1" type="some_third_value2">
            <element id="4" some_third_value2="1"/>
            <element id="5" some_third_value2="2"/>
            <element id="6" some_third_value2="3"/>
        </attribute>
    </data>
</workspace>    
  

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

1. Проблема была бы гораздо лучше проиллюстрирована, если бы она содержала пример ввода и ожидаемого результата.

2. Ну, это все еще загадка, потому что мы не видим, что делает вызываемый шаблон. Являются ли эти параметры полностью произвольными? Или они могут быть каким-то образом получены из @id ?

3. Можно ли увидеть шаблон вызова? Может быть, мы можем вычеркнуть это. Таким образом, избыточность также будет меньше. Но то, что мы не видим, мы не можем изменить.

4. Параметры и даже шаблоны могут сильно различаться в зависимости от идентификатора.

5. @user3124206 Возможно, вам следует использовать поиск для их определения. Кстати, в вашем примере показан один и тот же шаблон, вызываемый для каждого идентификатора.

Ответ №1:

Если важно, чтобы вызываемому шаблону был задан контекст сопоставляемого data_set , то я бы посоветовал вам сделать это следующим образом:

 <xsl:template match="/data">
    <workspace>
       <data>
            <xsl:apply-templates select="data_set[@id='id1' or id='id2' or id='id3']" />                  
       </data>
    </workspace>
</xsl:template>

<xsl:template match="data_set">            
    <xsl:call-template name="attribute">  
        <xsl:with-param name="id">
            <xsl:choose>
                <xsl:when test="@id='id1'">some_value1</xsl:when>
                <xsl:when test="@id='id2'">some_other_value1</xsl:when>
                <xsl:when test="@id='id3'">some_third_value1</xsl:when>
            </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="type">
            <xsl:choose>
                <xsl:when test="@id='id1'">some_value2</xsl:when>
                <xsl:when test="@id='id2'">some_other_value2</xsl:when>
                <xsl:when test="@id='id3'">some_third_value3</xsl:when>
            </xsl:choose>
        </xsl:with-param>
    </xsl:call-template>
</xsl:template>
  

Это предполагает, что вы используете XSLT 1.0. Может быть немного менее подробным в XSLT 2.0.

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

1. Спасибо, в итоге я сделал что-то в этом роде использовал mode то, что вы предложили, и получил результат, которым я достаточно доволен с точки зрения подробностей.