Правильное использование каждой группы в XSLT - PullRequest
0 голосов
/ 07 февраля 2012

У меня есть следующий пример XML:

<items>
    <item>
        <item_id>1</item_id>
        <item_name>item 1</item_name>
        <group_id>1</group_id>
        <group_name>group 1</group_name>
    </item>
    <item>
        <item_id>2</item_id>
        <item_name>item 2</item_name>
        <group_id>1</group_id>
        <group_name>group 1</group_name>
    </item>
    <item>
        <item_id>3</item_id>
        <item_name>item 3</item_name>
        <group_id>2</group_id>
        <group_name>group 2</group_name>
    </item>
</items>

, который мне нужно преобразовать в следующий формат CSV:

1,item 1
2,item 2
3,item 3
1,group 1
2,group 2

В xml, item_id всегда будет сопровождаться item_name.Имя элемента не всегда будет конкататным ('item_', #).Это может быть описание типа «зубная паста».Элементы никогда не будут повторяться в файле, но иногда сопряжение group_id-> group_name не всегда будет 1-1.В этом случае предпочтительнее использовать первое сопряжение.

Я выполняю это с помощью оператора 'for-each-group', но это выглядит немного странно.Есть ли недостатки этого подхода?Как лучше это сделать?

<xsl:template match="/">
    <xsl:call-template name="list_format">
        <xsl:with-param name="list" select="'item'"/>
    </xsl:call-template>
    <xsl:call-template name="list_format">
        <xsl:with-param name="list" select="'group'"/>
    </xsl:call-template>
</xsl:template>



<xsl:template name="list_format">
    <xsl:param name="list"/>

    <xsl:variable name="linefeed" select="'&#xA;'"></xsl:variable>
    <xsl:variable name="list_id" select="concat($list,'_id')"></xsl:variable>
    <xsl:variable name="list_name" select="concat($list,'_name')"></xsl:variable>

    <xsl:for-each-group select="/items/item" group-by="*[name()=$list_id]">
        <xsl:sort select="*[name()=$list_id]"/>
        <xsl:value-of select="*[name()=$list_id]"/>
        <xsl:text>,</xsl:text>
        <xsl:value-of select="*[name()=$list_name]"/> 
        <xsl:value-of select="$linefeed"/>
    </xsl:for-each-group>
</xsl:template>

Ответы [ 2 ]

1 голос
/ 07 февраля 2012

хммм .. на самом деле не является недостатком, но он не работает в XSLT 1.0, поскольку он не поддерживает for-each-group: - /

Не думаю, что вам понадобится решение XSLT 1.0 ... но я все еще публикую свою работу :) Проверьте это!

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>

  <xsl:template match="/items">
    <xsl:call-template name="items_grouping">
      <xsl:with-param name="list" select="'item'"/>
    </xsl:call-template>
    <xsl:call-template name="items_grouping">
      <xsl:with-param name="list" select="'group'"/>
    </xsl:call-template>
  </xsl:template>

    <xsl:template name="items_grouping">
    <xsl:param name="list"/>
    <xsl:variable name="linefeed" select="'&#xA;'"></xsl:variable>
    <xsl:variable name="list_id" select="concat($list,'_id')"></xsl:variable>
    <xsl:variable name="list_name" select="concat($list,'_name')"></xsl:variable>
    <xsl:for-each select="item">
      <xsl:for-each select="*[name()=$list_id and not(.= ../preceding-sibling::item/*[name()=$list_id]/.)]">
        <xsl:value-of select="concat(.,',')"/>
        <xsl:value-of select="../*[name()=$list_name]"/>
        <xsl:value-of select="$linefeed"/>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="text()"/>

</xsl:stylesheet>

Использовали ту же методологию, что и у вас ... единственное изменение 'preceding-sibling'
, а также для этого кода порядок дочерних узлов <item> не имеет значения

0 голосов
/ 07 февраля 2012

Вот простое и короткое решение XSLT 2.0 (согласно запросу) :

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:apply-templates/>
  <xsl:for-each-group select="/*/*/group_id" group-by=".">
    <xsl:value-of separator="," select="../*[starts-with(name(), 'group_')]"/>
    <xsl:text>&#xA;</xsl:text>
  </xsl:for-each-group>
 </xsl:template>

 <xsl:template match="item">
     <xsl:value-of separator="," select="*[starts-with(name(), 'item_')]"/>
   <xsl:text>&#xA;</xsl:text>
 </xsl:template>
</xsl:stylesheet>

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

<items>
    <item>
        <item_id>1</item_id>
        <item_name>item 1</item_name>
        <group_id>1</group_id>
        <group_name>group 1</group_name>
    </item>
    <item>
        <item_id>2</item_id>
        <item_name>item 2</item_name>
        <group_id>1</group_id>
        <group_name>group 1</group_name>
    </item>
    <item>
        <item_id>3</item_id>
        <item_name>item 3</item_name>
        <group_id>2</group_id>
        <group_name>group 2</group_name>
    </item>
</items>

желаемый, правильный результат получается :

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