2011-02-22 78 views
1

我正在處理一個樣式表,該樣式表從輸入文件以幾乎沒有分層格式輸出。每個部分都有一個非常平坦的層次結構,所以我一直在使用一種建議給我的分組方法 - 它將每個集合按第一個節點名稱進行分組,從而在平面部分創建出一個很好的層次結構。這種方法效果很好 - 我只需要修改它以說明我想跳過的元素。XSLT 2.0 - 使用分組嵌套元素

樣品輸入文件(注意:有每節的多個頭元件):

<Root> 
    <VolumeName>Volume 1 </VolumeName> 
    <Section> 
     <SectionName> Section1 </SectionName> 
     <Title> Title1 </Title> 
     <Header> NameOfDocument1 </Header> 
     <Header> Header1 </Header> 
     <Sub1> Sub1 first </Sub1> 
     <Sub1> Sub1 second </Sub1> 
     <Sub2> Sub2 first, Sub1 second </Sub2> 
     <Sub1> Sub1 third </Sub1> 
     <Sub2> Sub2 first, Sub1 third </Sub2> 
    </Section> 

    <Section> 
     <SectionName> Section2 </SectionName> 
     <Title> Title2 </Title> 
     <Header> Header2 </Header> 
     <Sub1> Sub1 first </Sub1> 
     <Sub1> Sub1 second </Sub1> 
     <Sub2> Sub2 first, Sub1 second </Sub2> 
     <Sub1> Sub1 third </Sub1> 
     <Sub2> Sub2 first, Sub1 third </Sub2> 
    </Section> 
</Root> 

樣品輸入代碼的輸出應爲:

<Volume1> 
    <Section1 Number="Section1" Name="NameOfDocument1" Title="Title1"> 
     <Header1> 
      <Step> 
       Sub1 first 
      </Step> 
      <Step> 
       Sub1 second 
       <Step> 
        Sub2 first, Sub1 second 
       </Step> 
      </Step> 
      <Step> 
       Sub1 third 
       <Step> 
        Sub2 first, Sub1 third 
       </Step> 
      </Step> 
     </Header1> 
    </Section1> 

    <Section2 Number="Section2" Name="concat('NameOfDocument','2')" Title="Title2"> 
      <Step> 
       Sub1 first 
      </Step> 
      <Step> 
       Sub1 second 
       <Step> 
        Sub2 first, Sub1 second 
       </Step> 
      </Step> 
      <Step> 
       Sub1 third 
       <Step> 
        Sub2 first, Sub1 third 
       </Step> 
      </Step> 
    </Section2> 
</Volume1> 

由於迪米特里Novatchev,我現在有一些代碼可以處理Section元素中的平坦部分。我有一個與Section元素相匹配的模板,然後我聲明一個元素並從SectionName,Title和Header中獲取信息,以填充元素將被調用的內容及其屬性。我想跳過SectionName,Title,有時候標題,但我不確定如何修改Dimitrie的代碼。任何建議將不勝感激!謝謝!

迪米特里的分組碼:

<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="/*"> 
     <Root> 
      <xsl:apply-templates select="*[1]"> 
       <xsl:with-param name="pScope" select="*"/> 
       <xsl:with-param name="pElemName" select="name(*[1])"/> 
      </xsl:apply-templates> 
     </Root> 
    </xsl:template> 

    <xsl:template match="*"> 
     <xsl:param name="pScope"/> 
     <xsl:param name="pElemName" select="'Step'"/> 
     <xsl:for-each-group select="$pScope" 
      group-starting-with="*[name()= name($pScope[1])]"> 
      <xsl:element name="{$pElemName}"> 
       <xsl:value-of select="."/> 
       <xsl:apply-templates select="current-group()[2]"> 
        <xsl:with-param name="pScope" 
         select="current-group()[position() > 1]"/> 
       </xsl:apply-templates> 
      </xsl:element> 
     </xsl:for-each-group> 
    </xsl:template> 
</xsl:stylesheet> 
+0

+1除了這是一個小修改,它仍然是一個很好的問題。 – 2011-02-22 22:33:02

回答

1

這裏是我的回答改編或最初的問題,產生現在的結果想:

<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="/*"> 
    <Root> 
    <xsl:element name="{translate(VolumeName,' ','')}"> 
    <xsl:apply-templates/> 
    </xsl:element> 
    </Root> 
</xsl:template> 

<xsl:template match="*"> 
    <xsl:param name="pScope"/> 
    <xsl:param name="pElemName" select="'Step'"/> 
    <xsl:for-each-group select="$pScope" 
     group-starting-with= 
     "*[name()= name($pScope[1])]"> 
    <xsl:element name="{$pElemName}"> 
    <xsl:value-of select="."/> 
    <xsl:apply-templates select="current-group()[2]"> 
    <xsl:with-param name="pScope" 
      select="current-group()[position() > 1]"/> 
    </xsl:apply-templates> 
    </xsl:element> 
    </xsl:for-each-group> 
</xsl:template> 

<xsl:template match="VolumeName"/> 

<xsl:template match="Section"> 
    <xsl:element name= 
     "{normalize-space(SectionName)}"> 
    <xsl:attribute name="Number" 
     select="normalize-space(SectionName)"/> 
    <xsl:attribute name="Name" select= 
    "concat('NameOfDocument', 
      count(preceding-sibling::Section)+1)"/> 
    <xsl:attribute name="Title" 
     select="normalize-space(Title)"/>" 

    <xsl:variable name="vOutput"> 
    <xsl:apply-templates select="*[1]"> 
    <xsl:with-param name="pScope" 
     select="Header[last()]/following-sibling::*"/> 
    <xsl:with-param name="pElemName" select= 
     "(normalize-space(Header[2]), 'Step')[last()]"/> 
    </xsl:apply-templates> 
    </xsl:variable> 

    <xsl:choose> 
    <xsl:when test="Header[2]"> 
    <xsl:element name="{normalize-space(Header[2])}"> 
     <xsl:sequence select="$vOutput"/> 
    </xsl:element> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:sequence select="$vOutput"/> 
    </xsl:otherwise> 
    </xsl:choose> 
    </xsl:element> 
</xsl:template> 
</xsl:stylesheet> 

當這種轉變是在所提供的XML文檔應用:

<Root> 
    <VolumeName>Volume 1 </VolumeName> 
    <Section> 
     <SectionName> Section1 </SectionName> 
     <Title> Title1 </Title> 
     <Header> NameOfDocument1 </Header> 
     <Header> Header1 </Header> 
     <Sub1> Sub1 first </Sub1> 
     <Sub1> Sub1 second </Sub1> 
     <Sub2> Sub2 first, Sub1 second </Sub2> 
     <Sub1> Sub1 third </Sub1> 
     <Sub2> Sub2 first, Sub1 third </Sub2> 
    </Section> 
    <Section> 
     <SectionName> Section2 </SectionName> 
     <Title> Title2 </Title> 
     <Header> Header2 </Header> 
     <Sub1> Sub1 first </Sub1> 
     <Sub1> Sub1 second </Sub1> 
     <Sub2> Sub2 first, Sub1 second </Sub2> 
     <Sub1> Sub1 third </Sub1> 
     <Sub2> Sub2 first, Sub1 third </Sub2> 
    </Section> 
</Root> 

想要的結果是:

<Root> 
    <Volume1> 
     <Section1 Number="Section1" Name="NameOfDocument1" Title="Title1">" 

      <Header1> 
       <Step> Sub1 first </Step> 
       <Step> Sub1 second 
        <Step> Sub2 first, Sub1 second </Step></Step> 
       <Step> Sub1 third 
        <Step> Sub2 first, Sub1 third </Step></Step> 
      </Header1> 
     </Section1> 
     <Section2 Number="Section2" Name="NameOfDocument2" Title="Title2">" 

      <Step> Sub1 first </Step> 
      <Step> Sub1 second 
       <Step> Sub2 first, Sub1 second </Step></Step> 
      <Step> Sub1 third 
       <Step> Sub2 first, Sub1 third </Step></Step> 
     </Section2> 
    </Volume1> 
</Root> 
1

我會堅持我的細粒度遍歷方法。這XSLT 1.0樣式:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="*"> 
     <xsl:param name="pNames" select="'|'"/> 
     <xsl:if test="not(contains($pNames,concat('|',name(),'|')))"> 
      <xsl:variable name="vNext" select="following-sibling::*[1]"/> 
      <xsl:variable name="vName"> 
       <xsl:apply-templates select="." mode="name"/> 
      </xsl:variable> 
      <xsl:element name="{$vName}"> 
       <xsl:apply-templates select="node()[1]"/> 
       <xsl:apply-templates select="$vNext"> 
        <xsl:with-param name="pNames" 
            select="concat($pNames,name(),'|')"/> 
       </xsl:apply-templates> 
      </xsl:element> 
      <xsl:apply-templates select="$vNext" mode="search"> 
       <xsl:with-param name="pNames" select="$pNames"/> 
       <xsl:with-param name="pSearch" select="name()"/> 
      </xsl:apply-templates> 
     </xsl:if> 
    </xsl:template> 
    <xsl:template match="*" mode="search"> 
     <xsl:param name="pNames"/> 
     <xsl:param name="pSearch"/> 
     <xsl:if test="not(contains($pNames,concat('|',name(),'|')))"> 
      <xsl:choose> 
       <xsl:when test="name()=$pSearch"> 
        <xsl:apply-templates select="."> 
         <xsl:with-param name="pNames" select="$pNames"/> 
        </xsl:apply-templates> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:apply-templates select="following-sibling::*[1]" 
             mode="search"> 
         <xsl:with-param name="pNames" select="$pNames"/> 
         <xsl:with-param name="pSearch" select="$pSearch"/> 
        </xsl:apply-templates> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:if> 
    </xsl:template> 
    <xsl:template match="SectionName|Title|Header[1]"> 
     <xsl:variable name="vName"> 
      <xsl:apply-templates select="." mode="name"/> 
     </xsl:variable> 
     <xsl:attribute name="{$vName}"> 
      <xsl:value-of select="."/> 
     </xsl:attribute> 
     <xsl:apply-templates select="following-sibling::*[1]"/> 
    </xsl:template> 
    <xsl:template match="SectionName" mode="name">Number</xsl:template> 
    <xsl:template match="Title" mode="name">Title</xsl:template> 
    <xsl:template match="Header[1]" mode="name">Name</xsl:template> 
    <xsl:template match="VolumeName|Section|Header" mode="name"> 
     <xsl:value-of select="translate((.|SectionName)[last()],' ','')"/> 
    </xsl:template> 
    <xsl:template match="Sub1|Sub2" mode="name">Step</xsl:template> 
    <xsl:template match="*" mode="name"> 
     <xsl:value-of select="name()"/> 
    </xsl:template> 
    <xsl:template match="VolumeName/text()|Header/text()"/> 
</xsl:stylesheet> 

輸出:

<Root> 
    <Volume1> 
     <Section1 Number=" Section1 " Title=" Title1 " 
        Name=" NameOfDocument1 "> 
      <Header1> 
       <Step> Sub1 first </Step> 
       <Step> Sub1 second 
        <Step> Sub2 first, Sub1 second </Step> 
       </Step> 
       <Step> Sub1 third 
        <Step> Sub2 first, Sub1 third </Step> 
       </Step> 
      </Header1> 
     </Section1> 
     <Section2 Number=" Section2 " Title=" Title2 " Name=" Header2 "> 
      <Step> Sub1 first </Step> 
      <Step> Sub1 second 
       <Step> Sub2 first, Sub1 second </Step> 
      </Step> 
      <Step> Sub1 third 
       <Step> Sub2 first, Sub1 third </Step> 
      </Step> 
     </Section2> 
    </Volume1> 
</Root> 

注意:由於計算的名字比映射更復雜,我用匹配方法的模式。

編輯:剝去只有空白的文本節點(感謝@ Dimitre的評論),所以現在也顯示在撒克遜的正確結果。

+0

+1。非常好的一個。 – Flack 2011-02-22 22:23:29

+0

@Alejandro:我只得到這樣的輸出:`<?XML版本= 「1.0」 編碼= 「UTF-8」?> \t` – 2011-02-23 03:21:44