根据从每个实体获取的行业对文档进行排序和显示

时间:2011-09-22 18:03:06

标签: xml xslt

我有一个.xml文件,其结构如下:

<documents>
<item>
    <title>Document Title</title>
    <customer>Customer Name1</customer>
    <description>Description 1 here</description>
    <image height="100" width="100"></image>
    <link filetype="pdf" language="English">/documents/document.pdf</link>
    <industry>Industry name 1</industry>
</item>
<item>
    <title>Document Title 2</title>
    <customer>Customer Name 2</customer>
    <description>Description 2 here</description>
    <image height="100" width="100"></image>
    <link filetype="pdf" language="English">/documents/document2.pdf</link>
    <industry>Industry name 2</industry>
</item>

我需要这个,最好使用XSL(因为我已经知道了一点,而且我很快就会接受),是这样的:

<h2>Industry name 1</h2>
<div class="doc">
<h3>Document Title</h3>
<p>Description 1 here <a href="/documents/document.pdf">Download!</a></p>
</div>

<h2>Industry name 2</h2>
<div class="doc">
<h3>Document Title 2</h3>
<p>Description 2 here <a href="/documents/document.pdf">Download!</a></p>
</div>

我完全难以理解的是,我是如何动态地从XML中获取行业,打印第一个行业,然后打印与该行业相关的所有文档,然后转到第二个行业,然后是第三个行业,第四个行业等等。我开始怀疑这是否可能,当我认为XSL必须实际存储每个行业的“标签”并比较它们以便看它是否已经拥有它。如果是,则不应打印,而只是打印其余信息。

我宁愿避免更改XML文件的架构,因为它已在所有已经用于其他目的的地方使用。但是,我意识到它可能是必须的。

另请注意,该文件完全未分类。添加的最新文件位于顶部,无论与之关联的行业“标记”如何。但是,这可以改变。

对我来说,如果它甚至可以使用纯XSL作为解析器,这是一个难以破解的难题吗?

1 个答案:

答案 0 :(得分:1)

此XSLT 1.0转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kItemByInd" match="item"
  use="industry"/>

 <xsl:template match=
  "item[generate-id()
       =
        generate-id(key('kItemByInd', industry)[1])
       ]
  ">
  <h2><xsl:value-of select="industry"/></h2>

  <xsl:apply-templates mode="inGroup"
   select="key('kItemByInd', industry)"/>
 </xsl:template>

 <xsl:template match="item"/>

 <xsl:template match="item" mode="inGroup">
   <div class="doc">
     <h3><xsl:value-of select="title"/></h3>
     <p>
       <xsl:value-of select="description"/>
       <a href="{link}"> Download!</a>
     </p>
   </div>
 </xsl:template>
</xsl:stylesheet>

应用于以下XML文档(通过添加一个项目从提供的文档中获取 - 以使其更有趣):

<documents>
    <item>
        <title>Document Title</title>
        <customer>Customer Name1</customer>
        <description>Description 1 here</description>
        <image height="100" width="100"></image>
        <link filetype="pdf" language="English">/documents/document.pdf</link>
        <industry>Industry name 1</industry>
    </item>
    <item>
        <title>Document Title 2</title>
        <customer>Customer Name 2</customer>
        <description>Description 2 here</description>
        <image height="100" width="100"></image>
        <link filetype="pdf" language="English">/documents/document2.pdf</link>
        <industry>Industry name 2</industry>
    </item>
    <item>
        <title>Document Title 3</title>
        <customer>Customer Name 3</customer>
        <description>Description 3 here</description>
        <image height="100" width="100"></image>
        <link filetype="pdf" language="English">/documents/document3.pdf</link>
        <industry>Industry name 1</industry>
    </item>
</documents>

生成想要的正确结果

<h2>Industry name 1</h2>
<div class="doc">
   <h3>Document Title</h3>
   <p>Description 1 here<a href="/documents/document.pdf"> Download!</a>
   </p>
</div>
<div class="doc">
   <h3>Document Title 3</h3>
   <p>Description 3 here<a href="/documents/document3.pdf"> Download!</a>
   </p>
</div>

<h2>Industry name 2</h2>
<div class="doc">
   <h3>Document Title 2</h3>
   <p>Description 2 here<a href="/documents/document2.pdf"> Download!</a>
   </p>
</div>

,它在浏览器中显示为

行业名称1

   

文件标题

   

说明1 Download!    

   

文件标题3

   

说明3 Download!    

行业名称2

   

文件标题2

   

说明2 Download!    

解释 Muenchian method for grouping

<强> II。 XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">
  <xsl:for-each-group select="item" group-by="industry">
    <h2><xsl:value-of select="industry"/></h2>
    <xsl:apply-templates select="current-group()"/>
  </xsl:for-each-group>
 </xsl:template>

  <xsl:template match="item">
   <div class="doc">
     <h3><xsl:value-of select="title"/></h3>
     <p>
       <xsl:value-of select="description"/>
       <a href="{link}"> Download!</a>
     </p>
   </div>
 </xsl:template>
</xsl:stylesheet>

当对同一XML文档(上面)应用此XSLT 2.0转换时,再次生成相同的正确结果

<强>解释

  1. <xsl:for-each-group>

  2. current-group()

  3. 更新:根据OP的请求,以下是XSLT 1.0解决方案的变体,它也按industry排序:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:key name="kItemByInd" match="item"
      use="industry"/>
    
     <xsl:template match="/*">
      <xsl:apply-templates select=
       "item[generate-id()
            =
             generate-id(key('kItemByInd', industry)[1])
            ]
       ">
        <xsl:sort select="industry"/>
       </xsl:apply-templates>
    
     </xsl:template>
    
     <xsl:template match="item">
      <h2><xsl:value-of select="industry"/></h2>
    
      <xsl:apply-templates mode="inGroup"
       select="key('kItemByInd', industry)"/>
     </xsl:template>
    
     <xsl:template match="item" mode="inGroup">
       <div class="doc">
         <h3><xsl:value-of select="title"/></h3>
         <p>
           <xsl:value-of select="description"/>
           <a href="{link}"> Download!</a>
         </p>
       </div>
     </xsl:template>
    </xsl:stylesheet>