XSLT: применить преобразование XML, за которым следует другое преобразование текста

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

Я хотел бы применить два преобразования к моему XML-файлу. Во-первых, я хочу сделать группировку по идентификатору. Затем я хотел бы выполнить некоторую обработку, чтобы удалить специальные символы.

По отдельности шаблоны работают нормально, но когда я пытаюсь их собрать вместе, у меня выводится xml и текстовый результат. Моя цель — иметь в выводе только текстовую часть и сохранять XML-часть только в качестве промежуточного шага.

Не могли бы вы рассказать мне, как правильно использовать атрибут режима? Я хотел бы сделать что-то похожее на это

   <xsl:template match = "">
         <xsl:apply-templates select = "XML_Part"/> ---> hide from the final output
         <xsl:apply-templates select = "Text_Part"/>
    </xsl:template>
    
    <xsl:template match = "" mode = "XML_Part">
    </xsl:template>
    
    <xsl:template match = "" mode = "Text_Part">
    </xsl:template>

XML-файл (входной)

<?xml version = "1.0" encoding = "UTF-8"?>
<wd:Report_Data xmlns:wd = "http://www.workday.org/">
  <wd:Report_Entry>
    <wd:id>1000</wd:id>
    <wd:name>Call-of-Duty</wd:name>
    <wd:price>50.12</wd:price>
    <wd:copy>0</wd:copy>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>1000</wd:id>
    <wd:name>Call-of-Duty</wd:name>
    <wd:price>60.0</wd:price>
    <wd:copy>1</wd:copy>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>2000</wd:id>
    <wd:name>Metal Slug</wd:name>
    <wd:price>75.00</wd:price>
    <wd:copy>0</wd:copy>
  </wd:Report_Entry>
  <wd:Report_Entry>
    <wd:id>3000</wd:id>
    <wd:name>Need For Speed</wd:name>
    <wd:price>40.00</wd:price>
    <wd:copy>0</wd:copy>
  </wd:Report_Entry>
</wd:Report_Data>

XSLT-шаблон для группировки

<xsl:template match = "/wd:Report_Data">
    <xsl:copy>
        <xsl:for-each-group select = "wd:Report_Entry" group-by = "wd:id">
            <xsl:copy>
                <xsl:copy-of select = "wd:id"/>
                <xsl:copy-of select = "wd:name"/>
                    <wd:price>
                        <xsl:value-of select = "sum(current-group()/wd:price)" />
                    </wd:price>                 
                <xsl:copy-of select = "wd:copy"/>
            </xsl:copy>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

XSLT для удаления специальных символов и отображения текстовой части

<xsl:template match = "wd:Report_Data/wd:Report_Entry">
    
    <xsl:value-of select = "wd:id"/>
    <xsl:text>|</xsl:text>
    <xsl:value-of select = "translate(wd:name,'-',' ')"/>
    <xsl:text>|</xsl:text>
    <xsl:value-of select = "wd:price"/>
    <xsl:text>|</xsl:text>
    <xsl:value-of select = "wd:copy"/>
  
</xsl:template>

Текущий выход

<wd:Report_Data xmlns:wd = "http://www.workday.org/">
   <wd:Report_Entry>
      <wd:id>1000</wd:id>
      <wd:name>Call of Duty</wd:name>
      <wd:price>110.12</wd:price>
      <wd:copy>0</wd:copy>
   </wd:Report_Entry>
   <wd:Report_Entry>
      <wd:id>2000</wd:id>
      <wd:name>Metal Slug</wd:name>
      <wd:price>75</wd:price>
      <wd:copy>0</wd:copy>
   </wd:Report_Entry>
   <wd:Report_Entry>
      <wd:id>3000</wd:id>
      <wd:name>Need For Speed</wd:name>
      <wd:price>40</wd:price>
      <wd:copy>0</wd:copy>
   </wd:Report_Entry>
</wd:Report_Data>
1000|Call of Duty|110.12|0
2000|Metal Slug|75.00|0
3000|Need For Speed|40.00|0

Ожидаемый результат

1000|Call of Duty|110.12|0
2000|Metal Slug|75.00|0
3000|Need For Speed|40.00|0

1
50
2

Ответы:

Решено

Нет необходимости связывать преобразования в цепочку. Вы можете сделать все это сразу, просто:

<xsl:stylesheet version = "2.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" 
xmlns:wd = "http://www.workday.org/" >
<xsl:output method = "text"/>

<xsl:template match = "/wd:Report_Data">
    <xsl:for-each-group select = "wd:Report_Entry" group-by = "wd:id">
        <xsl:value-of select = "wd:id, translate(wd:name, '-', ' '), sum(current-group()/wd:price), wd:copy" separator = "|"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

Если вам нужно, чтобы цена была отформатирована, как показано, измените:

sum(current-group()/wd:price)

к:

format-number(sum(current-group()/wd:price), '0.00')

Если вы хотите объединить преобразования (несмотря на то, что @y.arazim узнал, что в этом случае вам это не нужно), общая схема такова:

<xsl:variable name = "temp">
  <xsl:apply-templates mode = "phase1"/>
</xsl:variable>
<xsl:apply-templates select = "$temp" mode = "phase2"/>

И затем, конечно, прикрепите mode = "phase1" к шаблонам этапа 1 и mode = "phase2" к шаблонам этапа 2 — в идеале также поместите их в разные модули таблиц стилей.