xslt变换序列,maxOcurs = unbounded到嵌套元素

时间:2012-09-07 09:27:19

标签: xml xslt

我有以下XML:

<person-list>
  <pid>100</pid>
  <pname>Tom Jones</pname>
  <pdescription>Some Text</pdescription>
  <pid>101</pid>
  <pname>John Thomas</pname>
</person-list>

我想得到以下结果:

<person-list>
  <person>
    <pid>100</pid>
    <pname>Tom Jones</pname>
    <pdescription>Some Text</pdescription>
  </person>
  <person>
    <pid>101</pid>
    <pname>John Thomas</pname>
  </person>
</person-list>

有可能实现这个目标吗?

3 个答案:

答案 0 :(得分:2)

在XSLT1.0中执行此操作的一种方法是定义一个键,该键将 person-list 下的非pid元素组合在第一个最前面的 pid 元素< / p>

<xsl:key 
   name="fields" 
   match="person-list/*[not(self::pid)]" 
   use="generate-id(preceding-sibling::pid[1])" />

然后,对于 person-list 元素,您只需选择 pid 元素

<xsl:apply-templates select="pid" />

在匹配 pid 的模板中,您将创建 person 元素,并使用键输出其他元素:

<xsl:apply-templates select="key('fields', generate-id())" />

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="fields" match="person-list/*[not(self::pid)]" use="generate-id(preceding-sibling::pid[1])" />
   <xsl:template match="person-list">
      <person-list>
         <xsl:apply-templates select="pid" />
      </person-list>
   </xsl:template>

   <xsl:template match="pid">
      <person>
         <xsl:copy-of select="." />
         <xsl:apply-templates select="key('fields', generate-id())" />
      </person>
   </xsl:template>

   <xsl:template match="@*|node()" name="identity">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,输出以下内容

<person-list>
  <person>
    <pid>100</pid>
    <pname>Tom Jones</pname>
    <pdescription>Some Text</pdescription>
  </person>
  <person>
    <pid>101</pid>
    <pname>John Thomas</pname>
    <pdescription></pdescription>
  </person>
</person-list>

请注意,使用方法,您可以为每个人的输入文档添加更多字段,而无需修改XSLT。

另请注意使用'identity transform'复制现有元素。

答案 1 :(得分:1)

XSLT 2.0解决方案:

<xsl:template match="person-list">
  <xsl:copy>
    <xsl:for-each-group select="*" group-starting-with="pid">
      <person>
        <xsl:copy-of select="current-group()"/>
      </person>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

答案 2 :(得分:0)

是的,有办法做到这一点。例如,您可以找到“pid”元素,然后使用“follow-sibling”将它们与以下2个元素组合,并删除复制的标记:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <!-- IdentityTransform -->
 <xsl:template match="/ | @* | node()">
       <xsl:copy>
             <xsl:apply-templates select="@* | node()" />
       </xsl:copy>
</xsl:template>

<xsl:template match="/person-list/pid">
<person>
  <pid><xsl:value-of select="." /></pid>
  <pname><xsl:value-of select="following-sibling::*" /></pname>
  <pdescription><xsl:value-of select="following-sibling::*/following-sibling::*" />    </pdescription>
</person>
</xsl:template>
<xsl:template match="/person-list/pname" />
<xsl:template match="/person-list/pdescription"/>

</xsl:stylesheet>