使用XSLT对重复的XML数据进行分组

时间:2014-05-28 08:27:27

标签: xml xslt

我有一个XML需要转换为更好的项目分组。

  • 需要计算物品。
  • 我不知道会有多少只狗 列在清单中。
  • 我可能不知道有多少描述性的项目 狗会有。在这个例子中有三个,但它可能是 任何数字。如果这不灵活,那么固定数字就可以了。

优选XSLT 1.0

这可能吗?

我需要离开这个:

<table name = "dogs">
    <fields>
        <field name = "name" value = "dog1"></field>
        <field name = "age" value = "2"></field>
        <field name = "haircolor" value = "brown"></field>
        <field name = "name" value = "dog2"></field>
        <field name = "age" value = "10"></field>
        <field name = "haircolor" value = "white"></field>
        <field name = "name" value = "dog3"></field>
        <field name = "age" value = "7"></field>
        <field name = "haircolor" value = "black"></field>
        <field name = "name" value = "dog4"></field>
        <field name = "age" value = "4"></field>
        <field name = "haircolor" value = "brown"></field>
    </fields>
</table>

对此:

<dogs count = "4">
    <dog>
        <name>dog1</name>
        <age>2</age>
        <haircolor>brown</haircolor>
    </dog>
    <dog>
        <name>dog2</name>
        <age>10</age>
        <haircolor>white</haircolor>
    </dog>
    <dog>
        <name>dog3</name>
        <age>7</age>
        <haircolor>black</haircolor>
    </dog>
    <dog>
        <name>dog4</name>
        <age>4</age>
        <haircolor>brown</haircolor>
    </dog>
</dogs>

2 个答案:

答案 0 :(得分:1)

这是一种XSLT 1.0方法:

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

<xsl:output method="xml" indent="yes"/>

<xsl:template match="table">
  <xsl:element name="{@name}">
    <xsl:variable name="fields" select="fields/field[@name = current()/fields/field[1]/@name]"/>
    <xsl:attribute name="count"><xsl:value-of select="count($fields)"/></xsl:attribute>
    <xsl:apply-templates select="$fields"/>
  </xsl:element>
</xsl:template>

<xsl:template match="field">
  <xsl:variable name="this" select="."/>
  <xsl:element name="{../../@name}">
    <name><xsl:value-of select="@value"/></name>
    <xsl:apply-templates select="following-sibling::field[1][not(@name = $this/@name)]" mode="trans">
      <xsl:with-param name="head-name" select="$this/@name"/>
    </xsl:apply-templates>
  </xsl:element>

</xsl:template>

<xsl:template match="field" mode="trans">
  <xsl:param name="head-name"/>
  <xsl:element name="{@name}"><xsl:value-of select="@value"/></xsl:element>
  <xsl:apply-templates select="following-sibling::field[1][not(@name = $head-name)]" mode="trans">
    <xsl:with-param name="head-name" select="$head-name"/>
  </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

如果您想使用参数,那么代码可以使用

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

<xsl:param name="head-name" select="'name'"/>

<xsl:output method="xml" indent="yes"/>

<xsl:template match="table">
  <xsl:element name="{@name}">
    <xsl:variable name="fields" select="fields/field[@name = $head-name]"/>
    <xsl:attribute name="count"><xsl:value-of select="count($fields)"/></xsl:attribute>
    <xsl:apply-templates select="$fields"/>
  </xsl:element>
</xsl:template>

<xsl:template match="field">
  <xsl:variable name="this" select="."/>
  <xsl:element name="{../../@name}">
    <name><xsl:value-of select="@value"/></name>
    <xsl:apply-templates select="following-sibling::field[1][not(@name = $head-name)]" mode="trans"/>
  </xsl:element>
</xsl:template>

<xsl:template match="field" mode="trans">
  <xsl:element name="{@name}"><xsl:value-of select="@value"/></xsl:element>
  <xsl:apply-templates select="following-sibling::field[1][not(@name = $head-name)]" mode="trans">
    <xsl:with-param name="head-name" select="$head-name"/>
  </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

假设每组字段都以名称开头:

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="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="fields-by-lead" match="field[@name!='name']" use="generate-id(preceding-sibling::field[@name='name'][1])" />

<xsl:template match="/table">
    <xsl:variable name="names" select="fields/field[@name='name']" />
    <dogs count="{count($names)}">
        <xsl:for-each select="$names">
            <dog>
                <name><xsl:value-of select="@value"/></name>
                <xsl:for-each select="key('fields-by-lead', generate-id())">
                    <xsl:element name="{@name}">
                        <xsl:value-of select="@value"/>
                    </xsl:element>
                </xsl:for-each>
            </dog>
        </xsl:for-each>
    </dogs>
</xsl:template>

</xsl:stylesheet>

编辑:

以下修改为名称与第一个字段名称匹配的每个字段开始一个新组。

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="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="fields-by-lead" match="field" use="generate-id(preceding-sibling::field[@name=/table/fields/field[1]/@name][1])" />

<xsl:template match="/table">
    <xsl:variable name="lead-label" select="/table/fields/field[1]/@name" />
    <xsl:variable name="leads" select="fields/field[@name=$lead-label]" />
    <dogs count="{count($leads)}">
        <xsl:for-each select="$leads">
            <dog>
                <xsl:for-each select=". | key('fields-by-lead', generate-id())[@name!=$lead-label]">
                    <xsl:element name="{@name}">
                        <xsl:value-of select="@value"/>
                    </xsl:element>
                </xsl:for-each>
            </dog>
        </xsl:for-each>
    </dogs>
</xsl:template>

</xsl:stylesheet>