0

I have the following XML document which I need to convert to a new XML document with extra elements.

    <doc>
        <colleges>           
            <college>           
                <college-name>harvard</college-name>           
                    <members>
                        <!-- College staff-->
                        <staff>    
                            <employee id="2200010001" contract="full-time"/>                             
                            <employee id="2200010002" contract="temp"/>
                        </staff>
                        <!-- College students -->
                        <students>
                            <student id="1000020001"/>
                            <student id="1000020003"/>
                        </students>
                    </members>
            </college>
            <college>           
                <college-name>wharton</college-name>           
                    <members>
                        <!-- College staff-->
                        <staff>    
                            <employee id="2200010003" contract="full-time"/>                             
                            <employee id="2200010004" contract="temp"/>
                        </staff>
                        <!-- College students -->
                        <students>                               
                            <student id="1000020002"/>
                        </students>
                    </members>
                </college>
        </colleges>
        <students>                
            <student id="1000020001">        
                <personal>              
                    <name>
                        <firstname>Hillary</firstname>
                        <lastname>Clinton</lastname>
                    </name>                    
                    <!-- Student contact information -->
                    <contact-information>
                        <phone>+12123004000</phone>
                        <email>hillary@lostemail.com</email>
                    </contact-information>
                </personal>
                <registration>
                    <!-- Student university information -->                                     
                    <degree>
                        <type>undergrad</type>
                        <status>1</status>
                        <matriculated>yes</matriculated>                    
                    </degree>
                    <degree>
                        <type>masters</type>
                        <status>1</status>
                        <matriculated>yes</matriculated>                    
                    </degree>
                </registration>
            </student">
            <student id="1000020002">
                <personal>              
                    <name>
                        <firstname>Donald</firstname>
                        <lastname>Trump</lastname>
                    </name>
                    <!-- Student contact information -->
                    <contact-information>
                        <phone>+12123004001</phone>
                        <email>drumf@makeemailgreatagain.com</email>
                    </contact-information>
                </personal>
                <registration>
                    <!-- Student university information -->                                      
                    <degree>
                        <type>undergrad</type>
                        <status>1</status>
                        <matriculated>yes</matriculated>                    
                    </degree>
                    <degree>
                        <type>masters</type>
                        <status>1</status>
                        <matriculated>yes</matriculated>                    
                    </degree>
                </registration>
            </student">
        </students>
    </doc>

In the student element I need to extract the college name and insert it as element, so student section shows as following: (The remaining part is unchanged, I just added student section for simplicity and readability)

    <student id="1000020001">        
        <personal>              
            <name>
                <firstname>Hillary</firstname>
                <lastname>Clinton</lastname>
            </name>                    
            <!-- Student contact information -->
            <contact-information>
                <phone>+12123004000</phone>
                <email>hillary@lostemail.com</email>
            </contact-information>
        </personal>
            <registration>
                <!-- Student university information -->  
                <college-name>harvard</college-name>               
                <degree>
                    <type>undergrad</type>
                    <status>1</status>
                    <matriculated>yes</matriculated>                    
                </degree>
                <degree>
                    <type>masters</type>
                    <status>1</status>
                    <matriculated>yes</matriculated>                    
                </degree>
            </registration>
    </student">

I'm using XSLT using Identity rule, but my college-name is empty. Any suggestions?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="1.0">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <!-- Student registration-->
    <xsl:template match="student/registration">
        <registration>
            <xsl:apply-templates select="@* | *"/>
            <xsl:element name="college-name">
                <xsl:call-template name="extractCollegeName">
                        <xsl:with-param name="student-id" select="student/@id"/>
                </xsl:call-template>
            </xsl:element>
        </registration>
    </xsl:template>

    <!-- check student id for each college -->
    <xsl:template name="extractCollegeName">
        <xsl:param name="student-id"/>
        <xsl:for-each select="/doc/colleges/college">
            <xsl:if test="$student-id = members/students/student/@id">
                <xsl:value-of select="college-name"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>
Community
  • 1
  • 1
gogasca
  • 9,283
  • 6
  • 80
  • 125
  • 1
    Why aren't you using a **key** as shown here: http://stackoverflow.com/questions/40104423/xslt-checking-values-in-multiple-nodes – michael.hor257k Oct 20 '16 at 08:48

1 Answers1

1

you can use a key for student IDs such as

<xsl:key name="coll-name" match="college//student" use="@id"/>

from your template student/registration, get the college name by matching the key with the attribute of the parent node student, such as

key('coll-name', ancestor::student/@id)

then get the value of the college-name by using the xpath ancestor::college/college-name

whole stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="1.0">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="coll-name" match="college//student" use="@id"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <!-- Student registration-->
    <xsl:template match="student/registration">
        <registration>
            <xsl:element name="college-name">
                <xsl:value-of select="key('coll-name', ancestor::student/@id)/ancestor::college/college-name"/>
            </xsl:element>
            <xsl:apply-templates select="@* | *"/>
        </registration>
    </xsl:template>

</xsl:stylesheet>

see it working here

Joel M. Lamsen
  • 7,143
  • 1
  • 12
  • 14