开发者

XSLT - How to split up a parent's children

开发者 https://www.devze.com 2023-01-27 03:57 出处:网络
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 prog

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

精彩评论

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