Reputation: 61
I have an XML document with multiple instances and types of children within an element type, and need to display them both in order and with different formatting for each child type.
I've tried different combinations of for-each
and conditional choose
loops, but with no luck.
XML Segment:
<PLAY>
<PERSONAE>
<TITLE>Dramatis Personae</TITLE>
<PERSONA>CLAUDIUS, king of Denmark. </PERSONA>
<PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA>
<PERSONA>POLONIUS, lord chamberlain. </PERSONA>
<PERSONA>HORATIO, friend to Hamlet.</PERSONA>
<PERSONA>LAERTES, son to Polonius.</PERSONA>
<PERSONA>LUCIANUS, nephew to the king.</PERSONA>
<PGROUP>
<PERSONA>VOLTIMAND</PERSONA>
<PERSONA>CORNELIUS</PERSONA>
<PERSONA>ROSENCRANTZ</PERSONA>
<PERSONA>GUILDENSTERN</PERSONA>
<PERSONA>OSRIC</PERSONA>
<GRPDESCR>courtiers.</GRPDESCR>
</PGROUP>
<PERSONA>A Gentleman</PERSONA>
<PERSONA>A Priest. </PERSONA>
<PGROUP>
<PERSONA>MARCELLUS</PERSONA>
<PERSONA>BERNARDO</PERSONA>
<GRPDESCR>officers.</GRPDESCR>
</PGROUP>
XSL:
<h2><xsl:value-of select="PLAY/PERSONAE/TITLE" /></h2>
<xsl:for-each select="PLAY/PERSONAE/node()">
<xsl:choose>
<xsl:when test="PERSONA">
<xsl:value-of select="PERSONA" />
</xsl:when>
<xsl:when test="PGROUP">
<xsl:for-each select="PERSONA">
<xsl:value-of select="PERSONA" />
</xsl:for-each>
<xsl:value-of select="PGROUP" />
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:for-each>
Output
Dramatis Personae
VOLTIMANDMARCELLUS
Expected (Hopeful) Output
Dramatis Personae
CLAUDIUS, king of Denmark.
HAMLET, son to the late, and nephew to the present king.
POLONIUS, lord chamberlain.
HORATIO, friend to Hamlet.
LAERTES, son to Polonius.
LUCIANUS, nephew to the king.
VOLTIMAND
CORNELIUS
ROSENCRANTZ
GUILDENSTERN
OSRIC
A Gentleman
A Priest.
MARCELLUS
BERNARDO
FRANCISCO, a soldier.
REYNALDO, servant to Polonius.
Players.
Two Clowns, grave-diggers.
FORTINBRAS, prince of Norway.
A Captain.
English Ambassadors.
GERTRUDE, queen of Denmark, and mother to Hamlet.
OPHELIA, daughter to Polonius.
Lords, Ladies, Officers, Soldiers, Sailors, Messengers, and other Attendants.
Ghost of Hamlet's Father.
Every time, it either returns only the very first PERSONA child it parses, or it returns the first two PGROUP/PERSONA children. Can anyone see what I'm doing wrong?
Upvotes: 0
Views: 156
Reputation: 116993
If I am guessing correctly, you want an HTML output, not text. Here's a way you could achieve a result that, when rendered, will look like what you posted:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match="/PLAY">
<body>
<xsl:apply-templates/>
</body>
</xsl:template>
<xsl:template match="PERSONAE">
<h2>
<xsl:value-of select="TITLE" />
</h2>
<div>
<xsl:apply-templates select="PERSONA | PGROUP"/>
</div>
</xsl:template>
<xsl:template match="PERSONA">
<xsl:value-of select="." />
<br/>
</xsl:template>
<xsl:template match="PGROUP">
<p>
<xsl:apply-templates select="PERSONA"/>
</p>
</xsl:template>
</xsl:stylesheet>
When applied to the following test input:
<PLAY>
<PERSONAE>
<TITLE>Dramatis Personae</TITLE>
<PERSONA>CLAUDIUS, king of Denmark. </PERSONA>
<PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA>
<PERSONA>POLONIUS, lord chamberlain. </PERSONA>
<PERSONA>HORATIO, friend to Hamlet.</PERSONA>
<PERSONA>LAERTES, son to Polonius.</PERSONA>
<PERSONA>LUCIANUS, nephew to the king.</PERSONA>
<PGROUP>
<PERSONA>VOLTIMAND</PERSONA>
<PERSONA>CORNELIUS</PERSONA>
<PERSONA>ROSENCRANTZ</PERSONA>
<PERSONA>GUILDENSTERN</PERSONA>
<PERSONA>OSRIC</PERSONA>
<GRPDESCR>courtiers.</GRPDESCR>
</PGROUP>
<PERSONA>A Gentleman</PERSONA>
<PERSONA>A Priest. </PERSONA>
<PGROUP>
<PERSONA>MARCELLUS</PERSONA>
<PERSONA>BERNARDO</PERSONA>
<GRPDESCR>officers.</GRPDESCR>
</PGROUP>
</PERSONAE>
</PLAY>
the result will be:
<body>
<h2>Dramatis Personae</h2>
<p>CLAUDIUS, king of Denmark. <br>HAMLET, son to the late, and nephew to the present king.<br>POLONIUS, lord chamberlain. <br>HORATIO, friend to Hamlet.<br>LAERTES, son to Polonius.<br>LUCIANUS, nephew to the king.<br><p>VOLTIMAND<br>CORNELIUS<br>ROSENCRANTZ<br>GUILDENSTERN<br>OSRIC<br></p>A Gentleman<br>A Priest. <br><p>MARCELLUS<br>BERNARDO<br></p></p>
</body>
rendered as:
Upvotes: 1
Reputation: 15377
You probably want something more like:
<xsl:template match="PERSONAE">
<xsl:value-of select="TITLE"/>
<xsl:apply-templates select="PERSONA|PGROUP"/>
</xsl:template>
<xsl:template match="PGROUP">
<xsl:apply-templates select="PERSONA"/>
</xsl:template>
<xsl:template match="PERSONA">
<xsl:value-of select="."/>
</xsl:template>
Your:
<xsl:for-each select="PLAY/PERSONAE/node()">
is a just selecting the first node child of each PERSONAE
Upvotes: 1