开发者

XSLT - How to split up a parent's children

My xml structure contains a program as the parent of both certificates and courses. I want to split the structure up to create an independent listing of certificates and courses without the common program parent. The original structure is:

<root>
  <program>
    <program-name>Math</program-name>
    <certificate>...</certificate> <!-- There can 0 or more of these -->
    <course>...</course> <!-- There can 0 or more of these -->
  </program>
  <program>
    ...
  </program>
</root>

The output should look like so:

<root>
   <program-courses>
     <program>
       <program-name>Math</program-name>
       <course/> <!-- There can 0 or more of these -->
     </program>
     ...
   </program-courses>
   <program-certificates>
     <program>
       <program-name>Math</program-name>
       <certificate/> <!-- There can 0 or more of these -->
     </program>
     ...
   </program-certificates>
</root>

Update: Answered using Paul's suggestion for using a mode this is what the relevant portion of the xslt became:

<xsl:template match="root">
        <xsl:element name="root">
            <xsl:element name="program-courses">
                <xsl:apply-templates select="root/program-area" mode="course"/>
            </xsl:element>
            <xsl:element name="program-certificates">
                <xsl:apply-templates select="root/program-area" mode="certificate"/>
            </xsl:element>
        </xsl:element>           
    </xsl:template>

    <xsl:template match="program-area" mode="course">
        <xsl:element name="program-area">
           <!-- Get the name here -->
            <xsl:element name="course">
                <xsl:apply-templates select="course"/>
            </xsl:element>
        </xsl:element>
    </xsl:template>

    <xsl:template match="program-area" mode="certificate">
        <xsl:element name="program-area">
           <!-- Get the name here -->
            <xsl:element name="course">
                <xsl:apply-templates select="certificate"/>
            </xsl:element>
        </xsl:element>
    </xsl:template>

Note that thi开发者_如何学Cs solution is pared down from the actual one so it may not work as is against the original input.


  1. Selecting program elements, You could use @mode (on apply-templates and a corresponding template) to differentiate between whether you are operating within the output of program-courses or program-certificates

  2. From root, you could select program/course or program/certificate to generate the output program.

  3. From root, you could use for-each select="program" and for the part that is intended to output program-courses only extract the program-name and course element, and perform the corresponding extraction in the part that outputs program-certificates.


This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="program">
        <xsl:apply-templates select="course[1]|certificate[1]"/>
    </xsl:template>
    <xsl:template match="course[1]">
        <program-courses>
            <program>
                <xsl:apply-templates select="../*[not(self::certificate)]"
                                     mode="copy"/>
            </program>
        </program-courses>
    </xsl:template>
    <xsl:template match="certificate[1]">
        <program-certificates>
            <program>
                <xsl:apply-templates select="../*[not(self::course)]"
                                     mode="copy"/>
            </program>
        </program-certificates>
    </xsl:template>
    <xsl:template match="node()" mode="copy">
        <xsl:call-template name="identity"/>
    </xsl:template>
</xsl:stylesheet>

Output:

<root>
    <program-certificates>
        <program>
            <program-name>Math</program-name>
            <certificate>...</certificate>
        </program>
    </program-certificates>
    <program-courses>
        <program>
            <program-name>Math</program-name>
            <course>...</course>
        </program>
    </program-courses>
</root>

EDIT: If you want something more "push style" like your posted solution:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="node()" mode="certificate">
        <xsl:call-template name="identity"/>
    </xsl:template>
    <xsl:template match="node()" mode="course">
        <xsl:call-template name="identity"/>
    </xsl:template>
    <xsl:template match="program">
        <program-courses>
            <program>
                <xsl:apply-templates mode="course"/>
            </program>
        </program-courses>
        <program-certificates>
            <program>
                <xsl:apply-templates mode="certificate"/>
            </program>
        </program-certificates>
    </xsl:template>
    <xsl:template match="course" mode="certificate"/>
    <xsl:template match="certificate" mode="course"/>
</xsl:stylesheet>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜