如何在xslt中使用递归函数调用创建动态xml元素?

时间:2012-06-25 10:34:03

标签: xml xslt xpath

我想使用xslt将一种xml格式转换为另一种指定的格式。这是我的Xml文件。我必须通过在xslt中使用某种类型的递归调用来创建一些动态xml元素。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>Text1-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading1" /> 
        </w:pPr>
        <w:r>
            <w:t>Text2-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>Text3-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>Text4-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading2" /> 
        </w:pPr>
        <w:r>
            <w:t>Text5-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>Text6-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading3" /> 
        </w:pPr>
        <w:r>
            <w:t>Text7-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>Text8-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading1" /> 
        </w:pPr>
        <w:r>
            <w:t>Text9-</w:t>
        </w:r>  
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>Text10-</w:t>
        </w:r>  
    </w:p>


</w:body>
</w:document>

我需要的输出xml是:

<Document>
      <Paragraph>Text1-</Paragraph> 
      <Heading1>
         <Title>Text2-</Title>
         <Paragraph>Text3-</Paragraph> 
         <Paragraph>Text4-</Paragraph> 
         <Heading2>
            <Title>Text5-</Title>
            <Paragraph>Text6-</Paragraph> 
            <Heading3>
                <Title>Text7-</Title>
                <Paragraph>Text8-</Paragraph>  
            </Heading3>         
         </Heading2>
      <Heading1>
      <Heading1>
         <Title>Text9-</Title>
         <Paragraph>Text10-</Paragraph> 
       <Heading1>      
</Document>

请指导我一个摆脱这个问题的方法......

1 个答案:

答案 0 :(得分:1)

以下是样式表示例:

<xsl:stylesheet 
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xpath-default-namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
  xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs w mf">

<xsl:output indent="yes"/>

<xsl:function name="mf:group" as="element()*">
  <xsl:param name="paragraphs" as="element()*"/>
  <xsl:param name="level" as="xs:integer"/>
  <xsl:for-each-group select="$paragraphs" group-starting-with="p[pPr/pStyle/@w:val = concat('Heading', $level)]">
    <xsl:choose>
      <xsl:when test="self::p[pPr/pStyle/@w:val = concat('Heading', $level)]">
        <xsl:element name="Heading{$level}">
          <Title><xsl:value-of select="r/t"/></Title>
          <xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="current-group()"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:function>

<xsl:template match="document">
  <Document>
    <xsl:sequence select="mf:group(body/p, 1)"/>
  </Document>
</xsl:template>

<xsl:template match="p">
  <Paragraph>
    <xsl:value-of select="r/t"/>
  </Paragraph>
</xsl:template>

</xsl:stylesheet>

在样本输入文档中应用Saxon 9.4时,我得到以下结果:

<?xml version="1.0" encoding="UTF-8"?>
<Document>
   <Paragraph>Text1-</Paragraph>
   <Heading1>
      <Title>Text2-</Title>
      <Paragraph>Text3-</Paragraph>
      <Paragraph>Text4-</Paragraph>
      <Heading2>
         <Title>Text5-</Title>
         <Paragraph>Text6-</Paragraph>
         <Heading3>
            <Title>Text7-</Title>
            <Paragraph>Text8-</Paragraph>
         </Heading3>
      </Heading2>
   </Heading1>
   <Heading1>
      <Title>Text9-</Title>
      <Paragraph>Text10-</Paragraph>
   </Heading1>
</Document>