Карта сайта как структура папок - PullRequest
2 голосов
/ 22 мая 2011

Эй, ребята, я ищу способ показать карту сайта в виде структуры папок.

Так что в настоящее время карта сайта выглядит следующим образом:

Но вместо этого я ищу это:

  • http://mydomain.com/
    • категория
      • product1
      • product2
    • другая категория
      • product1
      • product2

Есть ли удобный способ сделать это?

Код карты сайта

...
<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 голосов
/ 22 мая 2011

В этих категориях преобразования 1.0 собираются только с помощью substring-before и substring-after.

Чтобы применить это преобразование к вашему случаю, вам просто нужно установить свой реальный домен в xsl:param и в xsl:key.

Обратите внимание, что ваш входной xml является фрагментом, и неясно, как вам нужен управляемый префикс пространства имен. Поэтому я проверил преобразование на примере XML без пространств имен. Если ваш исходный XML содержит префиксы пространства имен, преобразование должно быть настроено.


XSLT 1.0 протестировано под Saxon 6.5.5

<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 поддерживает ссылки на переменные.

XSLT 2.0 протестировано под Saxon-B 9.0.0.4J

<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>
0 голосов
/ 23 мая 2011

Вот простой шаблон, который должен делать то, что вам нужно:

  <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 начинается с текста в текущем, но не содержит никаких дополнительных / символов.

0 голосов
/ 22 мая 2011

I.Это решение 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
    • категория
      • product1
      • product2
    • другая категория
      • product1
      • product2
      • product3
  • mydomain2.com
    • другая категория
      • product3

Объяснение :

  1. Карта сайта gropus различных доменов,внутри них разные категории и внутри них разные продукты.

  2. Это двухпроходное решение.

  3. Первый проход маркирует каждый URL.Жетоны представлены word элементами.

  4. Второй проход применяется к результатам первого прохода мюнхенской группировки по ключам, содержащим одну, затем две, затем три части.

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()

...