2011-02-22 114 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