Reputation: 45
i have the following data set for a test case
<?xml version="1.0" encoding="UTF-8"?>
<STUDENTS_LIST dateGenerated="2014-01-01">
<STUDENTS>
<MALE>
<STUDENT_ID>10000</STUDENT_ID>
<F_NAME>REGGIE</F_NAME>
<M_NAME/>
<L_NAME>MILLER</L_NAME>
<DOB>
<YEAR>1980</YEAR>
</DOB>
<STUDENT_TYPE>MORNING</STUDENT_TYPE>
<STUDENT_REF>BLUE</STUDENT_REF>
<JOIN_DATE>04-20-2000</JOIN_DATE>
<NOTES/>
<FATHER_NAME>
<NAME>MILLER A</NAME>
</FATHER_NAME>
<MOTHER_NAME>
<NAME>MILLER B</NAME>
</MOTHER_NAME>
<REFRESH_DATE>04-14-2014</REFRESH_DATE>
<CORE_SUBJECTS>
<SUBJECT_A>CALCULUS A</SUBJECT_A>
<SUBJECT_B>CALCULUS B</SUBJECT_B>
<SUBJECT_C>PERFORMING ARTS</SUBJECT_C>
</CORE_SUBJECTS>
<OPT_SUBJECTS>
<SUBJECT_A>AMERICAN HISTORY</SUBJECT_A>
<SUBJECT_B/>
<SUBJECT_C/>
</OPT_SUBJECTS>
<STUDENT_KEY>ABC10000-1</STUDENT_KEY>
<STUDENT_KEY_CREATION_DATE>04-20-2000</STUDENT_KEY_CREATION_DATE>
</MALE>
<FEMALE>
<STUDENT_ID>10001</STUDENT_ID>
<F_NAME>REGINA</F_NAME>
<M_NAME/>
<L_NAME>MOON</L_NAME>
<DOB>
<YEAR>1980</YEAR>
</DOB>
<STUDENT_TYPE>MORNING</STUDENT_TYPE>
<STUDENT_REF>BLUE</STUDENT_REF>
<JOIN_DATE>04-20-2000</JOIN_DATE>
<NOTES/>
<FATHER_NAME>
<NAME>MOON A</NAME>
</FATHER_NAME>
<MOTHER_NAME>
<NAME>MOON B</NAME>
</MOTHER_NAME>
<REFRESH_DATE>04-14-2014</REFRESH_DATE>
<CORE_SUBJECTS>
<SUBJECT_A>CALCULUS A</SUBJECT_A>
<SUBJECT_B>CALCULUS B</SUBJECT_B>
<SUBJECT_C>PERFORMING ARTS</SUBJECT_C>
</CORE_SUBJECTS>
<OPT_SUBJECTS>
<SUBJECT_A>AMERICAN HISTORY</SUBJECT_A>
<SUBJECT_B/>
<SUBJECT_C/>
</OPT_SUBJECTS>
<STUDENT_KEY>ABC10000-1</STUDENT_KEY>
<STUDENT_KEY_CREATION_DATE>04-20-2000</STUDENT_KEY_CREATION_DATE>
</FEMALE>
</STUDENTS>
</STUDENTS_LIST>
which needs to be converted into the following xml using xslt
<?xml version="1.0" encoding="UTF-8"?>
<classified date="2014-01-01">
<students>
<student>
<student_id>10000</student_id>
<fname>REGGIE</fname>
<mname/>
<lname>MILLER</lname>
<sex>male</sex>
<data>student_type: MORNING, student_ref: BLUE, father_name: MILLER A,
mother_name: MILLER B, core_subjects : CALCULUS A, CALCULUS B, PERFORMING ARTS,
opt_subjects: AMERICAN HISTORY, student_key: ABC10000-1, student_key_creation_date:
04-20-2000, rec_refresh_date: 04-14-2014 </data>
<dob>
<year>1980</year>
</dob>
<joindate>04-20-2000</joindate>
</student>
<student>
<student_id>10001</student_id>
<fname>REGINA</fname>
<mname/>
<lname>MOON</lname>
<sex>female</sex>
<notes>student_type: MORNING, student_ref: BLUE, father_name: MOON A,
mother_name: MOON B, core_subjects : CALCULUS A, CALCULUS B, PERFORMING ARTS,
opt_subjects: AMERICAN HISTORY, student_key: ABC10000-1, student_key_creation_date:
04-20-2000, rec_refresh_date: 04-14-2014 </notes>
<dob>
<year>1980</year>
</dob>
<joindate>04-20-2000</joindate>
</student>
</students>
</classified>
I use the following XSLT provided by @Joel M. Lamsen in response to one of my other questions.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="STUDENT_TYPE|STUDENT_REF|FATHER_NAME|MOTHER_NAME|STUDENT_KEY|STUDENT_KEY_CREATION_DATE">
<xsl:value-of select="concat(name(), ': ', .)"/><xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="NOTES"/>
<xsl:template match="REFRESH_DATE">
<xsl:value-of select="concat('REC_REFRESH_DATE', ': ', .)"/><xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="CORE_SUBJECTS|OPT_SUBJECTS">
<xsl:value-of select="concat(name(), ': ')"/>
<xsl:for-each select="*[.!='']">
<xsl:choose>
<xsl:when test="position() != last()">
<xsl:value-of select="."/>
<xsl:text>, </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="STUDENT">
<xsl:copy>
<xsl:apply-templates select="STUDENT_ID|F_NAME|M_NAME|L_NAME|NOTES|DOB"/>
<NOTES>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="STUDENT_TYPE"/>
<xsl:apply-templates select="STUDENT_REF"/>
<xsl:apply-templates select="FATHER_NAME"/>
<xsl:apply-templates select="MOTHER_NAME"/>
<xsl:apply-templates select="CORE_SUBJECTS"/>
<xsl:apply-templates select="OPT_SUBJECTS"/>
<xsl:apply-templates select="STUDENT_KEY"/>
<xsl:apply-templates select="STUDENT_KEY_CREATION_DATE"/>
<xsl:apply-templates select="REFRESH_DATE"/>
</NOTES>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
the converted needs to be in the exact mapping order and needs to be sorted on male/female basis.
any help in this regard would be appreciated.
a previous example has already been solved.
regards reggie.
Upvotes: 1
Views: 86
Reputation: 7173
I have adapted the stylesheet below from @helderdarocha:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:template match="/">
<classified date="{STUDENTS_LIST/@dateGenerated}">
<students>
<xsl:apply-templates select="STUDENTS_LIST/STUDENTS/MALE|STUDENTS_LIST/STUDENTS/FEMALE"/>
</students>
</classified>
</xsl:template>
<xsl:template match="*" mode="notes">
<xsl:value-of select="translate(name(.), $uppercase, $lowercase)"/>
<xsl:text>: </xsl:text>
<xsl:choose>
<xsl:when test="child::text()">
<xsl:value-of select="child::text()"/>
<xsl:if test="not(self::REFRESH_DATE)">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="*[.!='']">
<xsl:value-of select="."/>
<xsl:text>, </xsl:text>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*" mode="tag">
<xsl:element name="{translate(name(.), $uppercase, $lowercase)}">
<xsl:choose>
<xsl:when test="name() = 'DOB'">
<year><xsl:value-of select="."/></year>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
<xsl:template match="MALE|FEMALE">
<student>
<xsl:apply-templates select="STUDENT_ID|F_NAME|M_NAME|L_NAME" mode="tag"/>
<sex><xsl:value-of select="translate(name(), $uppercase, $lowercase)"/></sex>
<xsl:if test="*[not(STUDENT_ID|F_NAME|M_NAME|L_NAME|DOB|JOIN_DATE)]">
<notes>
<xsl:apply-templates select="STUDENT_TYPE|STUDENT_REF|FATHER_NAME|MOTHER_NAME|CORE_SUBJECTS|OPT_SUBJECTS|STUDENT_KEY|STUDENT_KEY_CREATION_DATE" mode="notes"/>
<xsl:apply-templates select="REFRESH_DATE" mode="notes"/>
</notes>
</xsl:if>
<xsl:apply-templates select="DOB|JOIN_DATE" mode="tag"/>
</student>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 23627
You can combine nodes by extracting their text value in a template individually. This could be one note. It will add a comma after each one (except for the last()
one):
<xsl:template match="*" mode="notes">
<xsl:value-of select="translate(name(.), $uppercase, $lowercase)"/>
<xsl:text>: </xsl:text>
<xsl:value-of select="."/>
<xsl:if test="not(position() = last())">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
If you are using XSLT 2.0 you can use the lowercase
function to create elements in lowercase. If you are stuck to XSLT 1.0 you can use translate
with these two variables:
<xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
In the caller template you create the parent wrapper element. For example, this will choose some elements to be treated in a template called "tag" and the others in the template called "notes" above. All the notes will be wrapped inside a <notes>...</notes>
element:
<xsl:template match="STUDENT">
<student>
<xsl:apply-templates select="STUDENT_ID|F_NAME|M_NAME|L_NAME|DOB|JOIN_DATE" mode="tag"/>
<xsl:if test="*[not(STUDENT_ID|F_NAME|M_NAME|L_NAME|DOB|JOIN_DATE)]">
<notes><xsl:apply-templates mode="notes"/></notes>
</xsl:if>
</student>
</xsl:template>
You can create the tags using xsl:element
:
<xsl:template match="*" mode="tag">
<xsl:element name="{translate(name(.), $uppercase, $lowercase)}">
<xsl:choose>
<xsl:when test="name() = 'DOB'">
<year><xsl:value-of select="."/></year>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
Use the top level tag <xsl:strip-space elements="*"/>
to remove the spaces from the sources and you will probably be very close to the output that you expect.
Upvotes: 0