Transformation Using CMarkup

CMarkup has always provided the ability to do transformation procedurally, but with release 8.0 some features have been added to improve support for transformation, including to generate HTML. To understand CMarkup's transformation features, first consider the following simple XSL example, that takes an XML data file and matches it with an XSL style sheet to produce an XHTML result for display. The sample data contains items, each with name and ID.

<LIST>
<ITEM>
<NAME>John Smith</NAME>
<ID>7632</ID>
</ITEM>
<ITEM>
<NAME>Jane Smith</NAME>
<ID>1741</ID>
</ITEM>
</LIST>

The XSL style sheet has an xsl:template element containing XHTML tags as they will appear in the resulting document. Inside this xsl:template is an xsl:for-each element containing XHTML content that will be repeated for each result element of the select statement in the select attribute. Finally, the individual data fields of the result set are referenced with an xsl:value-of element.

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>Item List</h2>
<table border="1">
<tr>
<td>Name</td>
<td>ID</td>
</tr>
<xsl:for-each select="/*/ITEM">
<tr>
<td>
<xsl:value-of select="NAME"/>
</td>
<td>
<xsl:value-of select="ID"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

The resulting HTML page contains this simple table:

NameID
John Smith7632
Jane Smith1741

See Why To Avoid XSLT for more about XSL Transformation. The same exact transformation can be achieved with CMarkup and procedural logic, without using an XSL style sheet. This kind of transformation is very useful when you don't want to be dependent on the configuration and maintenance issues of having an external file specify the transformation.

CMarkup xml, html;
xml.Load( "itemdata.xml" );
html.AddElem( "html" );
html.IntoElem();
html.AddElem( "body" );
html.IntoElem();
html.AddElem( "table" );
html.SetAttrib( "border", 1 );
html.IntoElem();
html.AddElem( "tr" );
html.AddChildElem( "td", "Name" );
html.AddChildElem( "td", "ID" );
xml.ResetPos();
xml.FindElem();
xml.IntoElem();
while ( xml.FindElem("ITEM") )
{
	html.AddElem( "tr" );
	xml.FindChildElem( "NAME" );
	html.AddChildElem( "td", xml.GetChildData() );
	xml.FindChildElem( "ID" );
	html.AddChildElem( "td", xml.GetChildData() );
}

On the other hand, it can be useful to have an external file that provides part(s) of the HTML page. For example, you can just invent an element like <DATA_ROWS_HERE/> to use in your HTML file to be substituted programmatically. Developing an HTML page like this requires less specialized tools than developing an XSL style sheet does.

<html>
<body>
<h2>Item List</h2>
<table border="1">
<tr>
<td>Name</td>
<td>ID</td>
</tr>
<DATA_ROWS_HERE/>
</table>
</body>
</html>

The following example loads the above HTML file and substitutes the DATA_ROWS_HERE element with table rows containing data from the XML file. To find the DATA_ROWS_HERE element it utilizes the anywhere path available in CMarkup Developer, but you can also use the example code provided in Depth First Traversal.

html.Load( "template.htm" );
html.FindElem( "//DATA_ROWS_HERE" );
html.SavePos();
while ( xml.FindElem("ITEM") )
{
	html.AddElem( "tr" );
	xml.FindChildElem( "NAME" );
	html.AddChildElem( "td", xml.GetChildData() );
	xml.FindChildElem( "ID" );
	html.AddChildElem( "td", xml.GetChildData() );
}
html.RestorePos();
html.RemoveElem(); // delete placeholder
html.Save( "results.htm" );

CMarkup 8.0 has AddElem and SetData Flags for handling HTML entity references such as &nbsp; (which is not by default allowed in XML), and generating start tags without end tags, and empty tags with an extra space for XHTML such as <br />.

See also:

Transformation Example: Apples to Oranges
Simple Merge Example
Why To Avoid XSLT
The Versatile Way to Program XML