站点地图作为文件夹结构

时间:2011-05-22 10:37:11

标签: xml xslt sitemap

嘿伙计们, 我正在寻找一种将站点地图显示为文件夹结构的方法。

所以目前网站地图看起来像这样:

但相反,我正在寻找这个:

有没有方便的方法呢?

站点地图代码

...
<url>
  <loc>http://mydomain.com</loc>
  <changefreq>weekly</changefreq>
  <priority>1.00</priority>
</url>
<url>
  <loc>http://mydomain.com/category</loc>
  <changefreq>weekly</changefreq>
  <priority>0.80</priority>
</url>
...

** XSLT代码**

...
<ul> 
  <xsl:for-each select="xna:urlset/xna:url"> 
    <li><xsl:value-of select="xna:loc"/></li> 
  </xsl:for-each> 
</ul> 
...

3 个答案:

答案 0 :(得分:0)

<强>予。这个XSLT 1.0解决方案:

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

 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kLocByDomain" match="loc"
  use="word[1]"/>
 <xsl:key name="kLocByDomainAndCat" match="loc"
  use="concat(word[1], '+', word[2])"/>

 <xsl:key name="kLocByDomainCatProduct" match="loc"
  use="concat(word[1], '+', word[2], '+', word[3])"/>

 <xsl:template match="/*">
  <xsl:variable name="vrtfTokenized">
   <urls>
    <xsl:apply-templates/>
   </urls>
  </xsl:variable>

  <xsl:apply-templates mode="group"
   select="ext:node-set($vrtfTokenized)/*"/>
 </xsl:template>

 <xsl:template match="/*" mode="group">
  <h1>Sitemap</h1>

  <ul>
   <xsl:apply-templates mode="group" select=
    "loc[generate-id()
        =
         generate-id(key('kLocByDomain', word[1])[1])
        ]"/>
  </ul>
 </xsl:template>

 <xsl:template match="loc" mode="group">
  <li><xsl:value-of select="word[1]"/>
    <ul>
     <xsl:apply-templates mode="group2" select=
      "key('kLocByDomain', word[1])
             [generate-id()
             =
              generate-id(key('kLocByDomainAndCat',
                              concat(current()/word[1], '+', word[2])
                             )[1]
                          )
              ]"/>
    </ul>
  </li>
 </xsl:template>

 <xsl:template match="loc[word[2]]" mode="group2">
  <li><xsl:value-of select="word[2]"/>
    <ul>
     <xsl:apply-templates mode="group3" select=
      "key('kLocByDomainAndCat', concat(word[1], '+', word[2]))
             [generate-id()
             =
              generate-id(key('kLocByDomainCatProduct',
                              concat(current()/word[1], 
                                     '+', current()/word[2], 
                                     '+', word[3])
                             )[1]
                          )
              ]"/>
    </ul>
  </li>
 </xsl:template>

 <xsl:template match="loc[word[3]]" mode="group3">
  <li><xsl:value-of select="word[3]"/></li>
 </xsl:template>

 <xsl:template match="loc">
  <loc>
   <xsl:call-template name="tokenize">
    <xsl:with-param name="pText"
         select="substring-after(.,'http://')"/>
   </xsl:call-template>
  </loc>
 </xsl:template>

 <xsl:template name="tokenize">
  <xsl:param name="pText"/>

  <xsl:if test="string-length($pText)>0">
   <word>
    <xsl:value-of select=
     "substring-before(concat($pText,'/'), '/')"/>
   </word>
   <xsl:call-template name="tokenize">
    <xsl:with-param name="pText" select=
        "substring-after($pText,'/')"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>

 <xsl:template match="text()"/>
 <xsl:template match="text()" mode="group2"/>
 <xsl:template match="text()" mode="group3"/>
</xsl:stylesheet>

应用于以下XML文档时(基于提供的片段):

<site>
    <url>
        <loc>http://mydomain.com/</loc>
        <changefreq>weekly</changefreq>
        <priority>1.00</priority>
    </url>
    <url>
        <loc>http://mydomain.com/category</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url> ...
    <url>
        <loc>http://mydomain.com/category/product1</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url> ...
    <url>
        <loc>http://mydomain.com/category/product2</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url> ...
    <url>
        <loc>http://mydomain.com/other-category/product1</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url> ...
    <url>
        <loc>http://mydomain.com/other-category/product2</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url> ...
    <url>
        <loc>http://mydomain.com/other-category/product3</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url> ...
    <url>
        <loc>http://mydomain2.com/other-category/product3</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url> ...
</site>

生成想要的正确结果

    <h1>Sitemap</h1>
    <ul>
        <li>mydomain.com
            <ul>
                <li>category
                    <ul>
                        <li>product1</li>
                        <li>product2</li>
                    </ul></li>
                <li>other-category
                    <ul>
                        <li>product1</li>
                        <li>product2</li>
                        <li>product3</li>
                    </ul></li>
            </ul></li>
        <li>mydomain2.com
            <ul>
                <li>other-category
                    <ul>
                        <li>product3</li>
                    </ul></li>
            </ul></li>
    </ul>

-
在浏览器中显示为

网页

  • mydomain.com
    • 类别
      • 产品1
      • 产品2
    • 其他类
      • 产品1
      • 产品2
      • 产品3
  • mydomain2.com
    • 其他类
      • 产品3

<强>解释

  1. 网站地图包含不同的域名,其中包含不同的类别,其中包含不同的产品。

  2. 这是一个两遍解决方案。

  3. 第一遍标记每个网址。标记由word元素表示。

  4. 第二遍适用于第一遍Muenchian分组的结果,其中包含一个,然后是两个,然后是三个部分。

  5. <强> 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:strip-space elements="*"/>
    
     <xsl:template match="/*">
      <h1>Sitemap</h1>
      <ul>
       <xsl:for-each-group select="url/loc"
        group-by="tokenize(., '/')[3]"
       >
        <xsl:apply-templates select="."/>
       </xsl:for-each-group>
      </ul>
     </xsl:template>
    
     <xsl:template match="loc">
      <li><xsl:sequence select="tokenize(., '/')[3]"/>
       <ul>
        <xsl:for-each-group select=
         "current-group()[tokenize(., '/')[4]]"
         group-by="tokenize(., '/')[4]"
        >
         <xsl:apply-templates select="." mode="cat"/>
        </xsl:for-each-group>
       </ul>
      </li>
     </xsl:template>
    
     <xsl:template match="loc" mode="cat">
      <li><xsl:sequence select="tokenize(., '/')[4]"/>
       <ul>
        <xsl:for-each-group select=
         "current-group()[tokenize(., '/')[5]]"
         group-by="tokenize(., '/')[5]"
        >
         <xsl:apply-templates select="." mode="prod"/>
        </xsl:for-each-group>
       </ul>
      </li>
     </xsl:template>
    
     <xsl:template match="loc" mode="prod">
      <li><xsl:sequence select="tokenize(., '/')[5]"/></li>
     </xsl:template>
    </xsl:stylesheet>
    

    <强>解释

    我们使用了许多便于分组的XSLT 2.0功能:

    1. <xsl:for-each-group>

    2. current-group()

答案 1 :(得分:0)

在此1.0版本中,只使用substring-beforesubstring-after收集转换类别。

要将此转换应用于您的案例,您只需在xsl:paramxsl:key内设置真实域名。

请注意,您的输入xml是一个片段,并且您不清楚如何管理命名空间前缀。因此,我在没有命名空间的示例XML上测试了转换。如果源XML包含名称空间前缀,则应调整转换。


Saxon 6.5.5 下测试

XSLT 1.0

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <xsl:param name="mydomain" select="'http://mydomain.com/'"/>
    <xsl:key name="urlbyloc" match="url" use="substring-before(substring-after(loc,'http://mydomain.com/'),'/')"/>

    <xsl:template match="/*">
        <ul>
            <li><xsl:value-of select="$mydomain"/>
                <ul>
                    <xsl:apply-templates select="url[generate-id()=generate-id(key('urlbyloc', substring-before(substring-after(loc,$mydomain),'/'))[1]) and position()!=1]"/>
                </ul>
            </li>
        </ul>
    </xsl:template>

    <xsl:template match="url">
        <li>
            <xsl:value-of select="key('urlbyloc', '')/loc[contains(text(),substring-before(substring-after(current()/loc,$mydomain),'/'))]"/>
            <ul>
                <xsl:apply-templates select="key('urlbyloc', substring-before(substring-after(loc,$mydomain),'/'))/loc"/>
            </ul>
        </li>
    </xsl:template>

    <xsl:template match="loc">
        <li><xsl:value-of select="."/></li>
    </xsl:template>

    <xsl:template match="changefreq|priority"/>
</xsl:stylesheet>

此变换适用于以下输入:

<url-set>
    <url>
        <loc>http://mydomain.com</loc>
        <changefreq>weekly</changefreq>
        <priority>1.00</priority>
    </url>
    <url>
        <loc>http://mydomain.com/category</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url>
    <url>
        <loc>http://mydomain.com/category/prod1</loc>
        <changefreq>weekly</changefreq>
        <priority>1.00</priority>
    </url>
    <url>
        <loc>http://mydomain.com/category/prod2</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url>
    <url>
        <loc>http://mydomain.com/othercat</loc>
        <changefreq>weekly</changefreq>
        <priority>1.00</priority>
    </url>
    <url>
        <loc>http://mydomain.com/othercat/prod1</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url>
    <url>
        <loc>http://mydomain.com/othercat/prod2</loc>
        <changefreq>weekly</changefreq>
        <priority>0.80</priority>
    </url>
</url-set>

产地:

<ul>
   <li>http://mydomain.com/<ul>
         <li>http://mydomain.com/category<ul>
               <li>http://mydomain.com/category/prod1</li>
               <li>http://mydomain.com/category/prod2</li>
            </ul>
         </li>
         <li>http://mydomain.com/othercat<ul>
               <li>http://mydomain.com/othercat/prod1</li>
               <li>http://mydomain.com/othercat/prod2</li>
            </ul>
         </li>
      </ul>
   </li>
</ul>

使用XSLT 2.0用户定义函数,我们可以使转换更具可读性。此外,您需要在初始参数中指明您的域名,因为2.0 xsl:key支持变量引用。

Saxon-B 9.0.0.4J 下测试

XSLT 2.0

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:empo="http://stackoverflow.com/users/253811/empo"
    exclude-result-prefixes="empo">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:param name="mydomain" select="'http://mydomain.com/'"/>

    <xsl:function name="empo:get-category">
        <xsl:param name="loc"/>
        <xsl:param name="mydomain"/>
    <xsl:value-of select="substring-before(substring-after($loc,$mydomain),'/')"/>
  </xsl:function>

    <xsl:key name="urlbyloc" match="url" use="empo:get-category(loc,$mydomain)"/>

    <xsl:template match="/*">
        <ul>
            <li><xsl:value-of select="$mydomain"/>
                <ul>
                    <xsl:apply-templates select="url[generate-id()=generate-id(key('urlbyloc', empo:get-category(loc,$mydomain))[1]) and position()!=1]"/>
                </ul>
            </li>
        </ul>
    </xsl:template>

    <xsl:template match="url">
        <li>
            <xsl:value-of select="key('urlbyloc', '')/loc[contains(text(),empo:get-category(current()/loc,$mydomain))]"/>
            <ul>
                <xsl:apply-templates select="key('urlbyloc',empo:get-category(loc,$mydomain))/loc"/>
            </ul>
        </li>
    </xsl:template>

    <xsl:template match="loc">
        <li><xsl:value-of select="."/></li>
    </xsl:template>

    <xsl:template match="changefreq|priority"/>

</xsl:stylesheet>

答案 2 :(得分:0)

这是一个应该做你需要的简单模板:

  <xsl:template match="/">
    <xsl:apply-templates select="//url[1]" />
  </xsl:template>

  <xsl:template match="url">
    <xsl:param name="prefix" />
    <ul>
      <li><xsl:value-of select="substring-after(loc,$prefix)" /></li>
      <xsl:apply-templates select="../url[substring-after(loc,current()/loc) and not(contains(substring(substring-after(loc,current()/loc),2),'/'))]">
        <xsl:with-param name="prefix" select="concat(loc,'/')" />
      </xsl:apply-templates>
    </ul>
  </xsl:template>

第一个模板只是选择你的起点;在这种情况下,假设文档中的第一个URL包含您的根。在这里使用你需要的任何xpath; //url[loc='http://mydomain.com']也会这样做。

第二个模板完成工作,只需输出当前的loc字段,使用substring-after剥离之前的字段。然后,它会将自身应用于url字段以当前文本中的文本开头但没有任何其他loc个字符的任何其他/个节点。