Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用XSLT,如何根据节点的值分离节点?_Xslt_Xpath_Saxon - Fatal编程技术网

使用XSLT,如何根据节点的值分离节点?

使用XSLT,如何根据节点的值分离节点?,xslt,xpath,saxon,Xslt,Xpath,Saxon,我有一个非常简单的XML结构,我需要将其重新排序到分类的部分,而且,就我的一生而言,我不知道如何在XSLT中实现它(这并不是说我是专家) 基本上,原始XML看起来有点像: <things> <thing> <value>one</value> <type>a</type> </thing> <thing> <value>two</value>

我有一个非常简单的XML结构,我需要将其重新排序到分类的部分,而且,就我的一生而言,我不知道如何在XSLT中实现它(这并不是说我是专家)

基本上,原始XML看起来有点像:

<things>
  <thing>
    <value>one</value>
    <type>a</type>
  </thing>
  <thing>
    <value>two</value>
    <type>b</type>
  </thing>
  <thing>
    <value>thee</value>
    <type>b</type>
  </thing>
  <thing>
    <value>four</value>
    <type>a</type>
  </thing>
  <thing>
    <value>five</value>
    <type>d</type>
  </thing>
</things>

一
A.
二
B
你
B
四
A.
五
D
我需要输出如下内容:

<data>
  <a-things>
    <a>one</a>
    <a>four</a>
  </a-things>
  <b-things>
    <b>two</b>
    <b>three</b>
  </b-things>
  <d-things>
    <d>five</d>
  </d-things>
</data>

一
四
二
三
五
请注意,如果没有任何
元素,我就无法输出
,但我确实提前知道完整的类型列表是什么,而且它相当短,因此每个类型的手工编码模板绝对是可能的。感觉上我可能可以用
一起破解一些东西,但感觉上肯定有更多的…'templatey的方法。有人能帮忙吗


干杯。

当然,问这个问题让事情变得显而易见

我的解决方案确实使用了
,但我看不出它是怎么做到的,现在我想起来了。我的解决方案基本上如下所示:

<xsl:if test="/things/thing/type = 'a'">
  <a-things>
    <xsl:apply-templates select="/things/thing[type='a']" mode="a" />
  </a-things>
</if>

<xsl:template match="/things/thing[type='a']" mode="a">
    <a><xsl:value-of select="value"/>
</xsl:template>


对其他类型重复上述步骤。我已经把它编好了,它似乎工作得很好。

当然,问这个问题让它变得很明显

<a-things>
    <xsl:for-each select="thing[type = 'a']">
        <a><xsl:value-of select="./value" /></a>
    </xsl:for-each>
</a-things>
我的解决方案确实使用了
,但我看不出它是怎么做到的,现在我想起来了。我的解决方案基本上如下所示:

<xsl:if test="/things/thing/type = 'a'">
  <a-things>
    <xsl:apply-templates select="/things/thing[type='a']" mode="a" />
  </a-things>
</if>

<xsl:template match="/things/thing[type='a']" mode="a">
    <a><xsl:value-of select="value"/>
</xsl:template>

对其他类型重复上述步骤。我已经把它编码好了,它似乎工作得很好。


<a-things>
    <xsl:for-each select="thing[type = 'a']">
        <a><xsl:value-of select="./value" /></a>
    </xsl:for-each>
</a-things>
如果您想变得非常时髦,请使用参数替换
和谓词,并使用属性值模板:

<xsl:param name="type" />
<xsl:element name="{$type}-things">
    <xsl:for-each select="thing[type = $type]">
        <xsl:element name="{$type}"><xsl:value-of select="./value" /></xsl:element>
    </xsl:for-each>
</xsl:element>


如果您想变得非常时髦,请使用参数替换
和谓词,并使用属性值模板:

<xsl:param name="type" />
<xsl:element name="{$type}-things">
    <xsl:for-each select="thing[type = $type]">
        <xsl:element name="{$type}"><xsl:value-of select="./value" /></xsl:element>
    </xsl:for-each>
</xsl:element>

使用分组,您可以在不使用以下条件的情况下进行分组:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="things">
    <data>
      <xsl:for-each select="thing[not(type=preceding-sibling::thing/type)]">
        <xsl:variable name="type"><xsl:value-of select="type" /></xsl:variable>
          <xsl:element name="concat($type, '-things')">
            <xsl:for-each select="../thing[type=$type]">
              <xsl:element name="$type">
                <xsl:value-of select="value" />
              </xsl:element>
            </xsl:for-each>
          </xsl:element>
      </xsl:for-each>
    </data>
  </xsl:template>
</xsl:stylesheet>

使用分组,您可以在不使用以下条件的情况下进行分组:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="things">
    <data>
      <xsl:for-each select="thing[not(type=preceding-sibling::thing/type)]">
        <xsl:variable name="type"><xsl:value-of select="type" /></xsl:variable>
          <xsl:element name="concat($type, '-things')">
            <xsl:for-each select="../thing[type=$type]">
              <xsl:element name="$type">
                <xsl:value-of select="value" />
              </xsl:element>
            </xsl:for-each>
          </xsl:element>
      </xsl:for-each>
    </data>
  </xsl:template>
</xsl:stylesheet>

在使用Saxon时,请使用本机XSLT 2.0分组

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

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

    <xsl:template match="things">
        <data>
            <xsl:for-each-group select="thing" group-by="type">
                <xsl:element name="{concat(current-grouping-key(),'-things')}">
                    <xsl:for-each select="current-group()">
                        <xsl:element name="{current-grouping-key()}">
                            <xsl:value-of select="value" />
                        </xsl:element>
                    </xsl:for-each>
                </xsl:element>
            </xsl:for-each-group>
        </data>
    </xsl:template>

</xsl:stylesheet>

在使用Saxon时,请使用本机XSLT2.0分组

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

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

    <xsl:template match="things">
        <data>
            <xsl:for-each-group select="thing" group-by="type">
                <xsl:element name="{concat(current-grouping-key(),'-things')}">
                    <xsl:for-each select="current-group()">
                        <xsl:element name="{current-grouping-key()}">
                            <xsl:value-of select="value" />
                        </xsl:element>
                    </xsl:for-each>
                </xsl:element>
            </xsl:for-each-group>
        </data>
    </xsl:template>

</xsl:stylesheet>

通用解决方案是使用XSL键:

<xsl:key name="kThingByType" match="thing" use="type" />

<xsl:template match="things">
  <xsl:copy>
    <xsl:apply-templates select="thing" mode="group">
      <xsl:sort select="type" />
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

<xsl:template match="thing" mode="group">
  <xsl:variable name="wholeGroup" select="key('kThingByType', type)" />
  <xsl:if test="generate-id() = generate-id($wholeGroup[1])">
    <xsl:element name="{type}-thing">
      <xsl:copy-of select="$wholeGroup/value" />
    </xsl:element>
  </xsl:if>
</xsl:template>

上述收益率:

<things>
  <a-thing>
    <value>one</value>
    <value>four</value>
  </a-thing>
  <b-thing>
    <value>two</value>
    <value>thee</value>
  </b-thing>
  <d-thing>
    <value>five</value>
  </d-thing>
</things>

一
四
二
你
五

通用解决方案是使用XSL键:

<xsl:key name="kThingByType" match="thing" use="type" />

<xsl:template match="things">
  <xsl:copy>
    <xsl:apply-templates select="thing" mode="group">
      <xsl:sort select="type" />
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

<xsl:template match="thing" mode="group">
  <xsl:variable name="wholeGroup" select="key('kThingByType', type)" />
  <xsl:if test="generate-id() = generate-id($wholeGroup[1])">
    <xsl:element name="{type}-thing">
      <xsl:copy-of select="$wholeGroup/value" />
    </xsl:element>
  </xsl:if>
</xsl:template>

上述收益率:

<things>
  <a-thing>
    <value>one</value>
    <value>four</value>
  </a-thing>
  <b-thing>
    <value>two</value>
    <value>thee</value>
  </b-thing>
  <d-thing>
    <value>five</value>
  </d-thing>
</things>

一
四
二
你
五

在XSLT2中,您可以非常优雅地执行此操作。假设您有一个模板,用于在将每个内容包装到元素中之前对其进行格式化:

然后,您可以为每个唯一类型(示例输入中的a、b、d)调用该函数来构建整个输出,您完成了:

<xsl:template match="/">
    <data>
        <xsl:sequence select="
            for $type in distinct-values(things/thing/type/text())
            return my:things-group($type, /things/thing)
            "/>
    </data>
</xsl:template>

在XSLT2中,您可以非常优雅地执行此操作。假设您有一个模板,用于在将每个内容包装到元素中之前对其进行格式化:

然后,您可以为每个唯一类型(示例输入中的a、b、d)调用该函数来构建整个输出,您完成了:

<xsl:template match="/">
    <data>
        <xsl:sequence select="
            for $type in distinct-values(things/thing/type/text())
            return my:things-group($type, /things/thing)
            "/>
    </data>
</xsl:template>