4

我是 XSLT 的初学者。

我的源 XML 如下:

<Passengers>
    <Passenger type="A" id="P1"/>
    <Passenger type="A" id="P2"/>
    <Passenger type="B" id="P3"/>
    <Passenger type="C" id="P4"/>
</Passengers>

输出应如下所示:

<Pax_Items>
     <Item>
         <Type>A</Type>
         <Count>2</Count>
     </Item>
     <Item>
         <Type>B</Type>
         <Count>1</Count>
     </Item>
     <Item>
         <Type>C</Type>
         <Count>1</Count>
     </Item>
</Pax_Items>

我创建了如下 XSLT

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

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
        <xsl:variable name="filter" select="'TK,AJ'"/>

    <xsl:template match="Passengers">
        <xsl:element name="Pax_Items">
            <xsl:apply-templates select="Passenger"/>
        </xsl:element>
    </xsl:template>

        <xsl:template match="Passenger">
              <xsl:element name="Item">
                     <xsl:element name="Type">
                           <xsl:value-of select="@type"/>
                     </xsl:element>
                     <xsl:element name="Count">
                           <xsl:value-of select="count(//Passenger[@type=current()/@type])"/>
                     </xsl:element>
              </xsl:element>
    </xsl:template>
</xsl:stylesheet>

使用上面的 XSLT,我得到了以下输出:

<Pax_Items>
  <Item>
    <Type>A</Type>
    <Count>2</Count>
  </Item>
  <Item>
    <Type>A</Type>
    <Count>2</Count>
  </Item>
  <Item>
    <Type>B</Type>
    <Count>1</Count>
  </Item>
  <Item>
    <Type>C</Type>
    <Count>1</Count>
  </Item>
</Pax_Items>

我怎样才能省略或跳过重复的元素?请帮忙。

4

2 回答 2

7

这实际上是分组问题的一个很好的例子。在 XSLT1.0 中,进行分组的最有效方法是使用一种称为“Muenchian Grouping”的技术,因此可能值得学习这一点。

在这种情况下,您希望通过其@type属性对乘客元素进行分组,因此您将定义一个键来执行此操作

<xsl:key name="Passengers" match="Passenger" use="@type"/>

然后,您需要为其@type属性选择恰好是该元素在组中第一次出现的Passenger元素。这是按如下方式完成的:

<xsl:apply-templates 
    select="Passenger[generate-id() = generate-id(key('Passengers', @type)[1])]"/>

注意generate-id的使用,它为一个节点生成一个唯一的 ID,允许比较两个节点。

然后,要计算组中出现的次数,很简单

<xsl:value-of select="count(key('Passengers', @type))"/>

这是完整的 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
   <xsl:key name="Passengers" match="Passenger" use="@type"/>

   <xsl:template match="Passengers">
      <Pax_Items>
         <xsl:apply-templates select="Passenger[generate-id() = generate-id(key('Passengers', @type)[1])]"/>
      </Pax_Items>
   </xsl:template>

   <xsl:template match="Passenger">
      <Item>
         <Type>
            <xsl:value-of select="@type"/>
         </Type>
         <Count>
            <xsl:value-of select="count(key('Passengers', @type))"/>
         </Count>
      </Item>
   </xsl:template>
</xsl:stylesheet>

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

<Pax_Items>
   <Item>
      <Type>A</Type>
      <Count>2</Count>
   </Item>
   <Item>
      <Type>B</Type>
      <Count>1</Count>
   </Item>
   <Item>
      <Type>C</Type>
      <Count>1</Count>
   </Item>
</Pax_Items>

另请注意,没有真正的理由使用xsl:element来输出静态元素。直接写出元素即可。

于 2012-10-25T13:24:12.177 回答
2

passenger如下更新您的模板;我添加了 if 条件来检查重复节点,

<xsl:template match="Passenger">
    <xsl:if test="not(preceding-sibling::Passenger[@type = current()/@type])">
      <xsl:element name="Item">
        <xsl:element name="Type">
          <xsl:value-of select="@type"/>
        </xsl:element>
        <xsl:element name="Count">
          <xsl:value-of select="count(//Passenger[@type=current()/@type])"/>
        </xsl:element>
      </xsl:element>
    </xsl:if>
  </xsl:template>
于 2012-10-25T13:10:13.187 回答