0

我有以下 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>

有可能实现这一目标吗?

4

3 回答 3

2

在 XSLT1.0 中执行此操作的一种方法是定义一个键,将person-list下的非 pid 元素按最前面的pid元素分组

<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。

还要注意使用“身份转换”来复制现有元素。

于 2012-09-07T10:05:48.980 回答
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>
于 2012-09-07T11:09:31.363 回答
0

是的,有办法做到这一点。例如,您可以找到“pid”元素,然后使用“following-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>
于 2012-09-07T09:55:35.360 回答