2014-02-15 123 views
0

我希望得到一些關於如何使用XSLT 1.0在無序列表中將具有相同名稱的相鄰元素分組的相關建議。使用XSLT 1.0分組相鄰項目

下面是一些示例XML:

<Article> 
    <TextContent> 
    <p>lorem</p> 
    <VisualContent id="1" /> 
    <VisualContent id="2" /> 
    <VisualContent id="3" /> 
    <p>ipsum</p> 
    <VisualContent id="4" /> 
    <p>dolor</p> 
    <VisualContent id="5" /> 
    </TextContent> 
</Article> 

這是我想要的輸出:

<Article> 
    <HtmlContent> 
    <p>lorem</p> 
    <ul> 
     <li><img data-id="1" /></li> 
     <li><img data-id="2" /></li> 
     <li><img data-id="3" /></li> 
    </ul> 
    <p>ipsum</p> 
    <img data-id="4" /> 
    <p>dolor</p> 
    <img data-id="5" /> 
    </HtmlContent> 
</Article> 

遺憾的是,XSLT 1.0是這一個嚴格的要求。任何建議將不勝感激。

回答

2

我跳過其中<TextContent>變成<HtmlContent><VisualContent id="n" />成爲<img data-id="n" />因爲這個問題是非常困難沒有這些分心的部分。

我選擇的方法查看名稱爲而不是的第一個前面的兄弟姐妹與當前元素的名稱相同。該同級的唯一ID是由同一個名字的相鄰的元件可以被分組的關鍵是:

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

<xsl:key name="prevByName" match="TextContent/*" use="generate-id(preceding-sibling::*[not(name()=name(current()))][1])" /> 

<xsl:template match="/"> 
<Article><TextContent> 
    <xsl:for-each select="Article/TextContent/*[generate-id()=generate-id(key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))[1])]"> 
     <xsl:variable name="myGroup" select="key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))" /> 
     <xsl:choose> 
      <xsl:when test="count($myGroup) > 1"> 
       <ul> 
        <xsl:for-each select="$myGroup"> 
        <li><xsl:copy-of select="."/></li> 
        </xsl:for-each> 
       </ul> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy-of select="."/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:for-each> 
</TextContent></Article> 
</xsl:template> 
</xsl:stylesheet> 

當施加到您的輸入例如,下面的結果產生:

<?xml version="1.0" encoding="utf-8"?> 
<Article> 
    <TextContent> 
     <p>lorem</p> 
     <ul> 
     <li> 
      <VisualContent id="1"/> 
     </li> 
     <li> 
      <VisualContent id="2"/> 
     </li> 
     <li> 
      <VisualContent id="3"/> 
     </li> 
     </ul> 
     <p>ipsum</p> 
     <VisualContent id="4"/> 
     <p>dolor</p> 
     <VisualContent id="5"/> 
    </TextContent> 
</Article> 

編輯: 這裏的一個修改的版本,只有組相鄰 「VisualContent」 元素:

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

<xsl:key name="prevByName" match="TextContent/*" use="generate-id(preceding-sibling::*[not(name()=name(current()))][1])" /> 

<xsl:template match="/Article/TextContent"> 
    <Article><TextContent> 
     <xsl:apply-templates select="*"/> 
    </TextContent></Article> 
</xsl:template> 

<xsl:template match="TextContent/*[not(self::VisualContent)]"> 
    <xsl:copy-of select="."/> 
</xsl:template> 

<xsl:template match="VisualContent[generate-id()=generate-id(key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))[1])]"> 
<xsl:variable name="myGroup" select="key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))" /> 
    <xsl:choose> 
     <xsl:when test="count($myGroup) > 1"> 
      <ul> 
       <xsl:for-each select="$myGroup"> 
       <li><xsl:copy-of select="."/></li> 
       </xsl:for-each> 
      </ul> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:copy-of select="."/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

</xsl:stylesheet> 

這很可能使用了一些精簡,但我認爲原則是清楚的,我需要得到一些睡眠...

+0

我想了解您的代碼,但是我們可以在沒有的情況下執行此操作,並且僅使用模板?因爲我學到的是在XSLT中使用模板是一種經典的方式。無論如何,謝謝你的解決方案。它演示了很多東西 – spiderman

+0

這有助於很多,謝謝@ michael.hor257k!有沒有一種方法可以讓這個只將相鄰的「VisualContent」元素分組?例如,我使用的輸入的某些部分有相鄰的「p」標籤,但我不希望那些顯示在ul中的標籤。 – sauceboat

+0

@sauceboat我在回答中添加了修改後的版本。 –

0

我也是XSLT的新手。

這不是您的預期輸出,我無法得到<ul>,但看看您是否可以在此基礎上構建。我也會嘗試。

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" encoding="UTF-8" /> 
    <xsl:template match="/"> 
     <Article> 
      <HtmlContent> 
       <xsl:apply-templates /> 
      </HtmlContent> 
     </Article> 
    </xsl:template> 

    <xsl:template match="VisualContent"> 
     <li> 
      <xsl:element name="img"> 
       <xsl:attribute name="date-id"><xsl:number/></xsl:attribute> 
      </xsl:element> 
     </li> 
    </xsl:template> 

    <xsl:template match="p"> 
     <xsl:element name="p"> 
      <xsl:apply-templates /> 
     </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

這是輸出:

<Article> 
    <HtmlContent> 
     <p>lorem</p> 
     <li><img date-id="1" /></li> 
     <li><img date-id="2" /></li> 
     <li><img date-id="3" /></li> 
     <p>ipsum</p> 
     <li><img date-id="4" /></li> 
     <p>dolor</p> 
     <li><img date-id="5" /></li> 
    </HtmlContent> 
</Article> 
0

找出後,我需要在xsltproc(1.1.29)的最新版本,我進一步改變了樣式表。分組只適用於TextContent的子項,但我需要分組來處理任何嵌套級別。

這是我輸入:

<Article> 
    <TextContent> 
     <p>lorem</p> 
     <VisualContent id="1" /> 
     <VisualContent id="2" /> 
     <VisualContent id="3" /> 
     <p>ipsum</p> 
     <VisualContent id="4" /> 
     <p>dolor</p> 
     <p>sit</p> 
     <VisualContent id="5" /> 
    </TextContent> 
    <p>amet</p> 
    <VisualContent id="6" /> 
    <VisualContent id="7" /> 
    <p>consectetur</p> 
    <VisualContent id="8" /> 
</Article> 

我用下面的樣式表:

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

    <!-- IdentityTransform --> 
    <xsl:template match="/ | @* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:key name="prevByName" match="*/*" use="generate-id(preceding-sibling::*[not(name()=name(current()))][1])" /> 

    <xsl:template match="VisualContent"> 
     <xsl:if test="generate-id()=generate-id(key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))[1])"> 
      <xsl:variable name="myGroup" select="key('prevByName', generate-id(preceding-sibling::*[not(name()=name(current()))][1]))" /> 
      <xsl:choose> 
       <xsl:when test="count($myGroup) > 1"> 
        <ul> 
         <xsl:for-each select="$myGroup"> 
          <li> 
           <xsl:copy-of select="."/> 
          </li> 
         </xsl:for-each> 
        </ul> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:copy-of select="."/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

現在,上的任何元素的水平分組的作品。 :-)

<?xml version="1.0" encoding="utf-8"?> 
<Article> 
    <TextContent> 
     <p>lorem</p> 
     <ul><li><VisualContent id="1"/></li><li><VisualContent id="2"/></li><li><VisualContent id="3"/></li></ul> 


     <p>ipsum</p> 
     <VisualContent id="4"/> 
     <p>dolor</p> 
     <p>sit</p> 
     <VisualContent id="5"/> 
    </TextContent> 
    <p>amet</p> 
    <ul><li><VisualContent id="6"/></li><li><VisualContent id="7"/></li></ul> 

    <p>consectetur</p> 
    <VisualContent id="8"/> 
</Article>