Reputation: 6982
I'm trying to add a processing instruction node to an existing XML document to have a XSL transformation applied to the document when displayed in a browser. I looked up how to do it using libxml++
classes but couldn't find it out, so I tried using libxml2
. This is what I came up with:
xmlpp::Document* Doc = Parser->get_document();
// Set processing instruction for stylesheet
const xmlNodePtr PINode = xmlNewDocPI(
Doc->cobj(),
reinterpret_cast<xmlChar*>("xml-stylesheet"),
reinterpret_cast<xmlChar*>("href=\"../stylesheet.xslt\" type=\"text/xsl\"")
);
if (PINode == NULL) {
// Never get here
}
Doc->write_to_file_formatted("mydoc.xml", "utf-8");
The processing instruction node is not written into the document. So what am I missing here?
Upvotes: 2
Views: 1273
Reputation: 243479
Adding a processing instruction to an XML document can be done in pure XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<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>
<xsl:template match="/">
<xsl:processing-instruction name="xml-stylesheet">
<xsl:text>href="../stylesheet.xslt" type="text/xsl"</xsl:text>
</xsl:processing-instruction>
<xsl:text>
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied to any XML document, such as the one below:
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
the wanted result is produced:
<?xml-stylesheet href="../stylesheet.xslt" type="text/xsl"?>
<nums>
<num>01</num>
<num>02</num>
<num>03</num>
<num>04</num>
<num>05</num>
<num>06</num>
<num>07</num>
<num>08</num>
<num>09</num>
<num>10</num>
</nums>
Upvotes: 1
Reputation: 6982
It turns out that just calling xmlNewDocPI
is not enough. It creates the processing instruction node and somehow associates it to the document but it doesn't actually attach it to the document.
For that purpose some of the xmlAdd*
functions must be called and, since I need the PI to be included right below the XML declaration and not nested within the documents root node, I had to use the following:
xmlAddPrevSibling(Doc->get_root_node()->cobj(), PINode);
It looks kind of hackish but works. So the full snippet for the working code gets like this:
xmlpp::Document* Doc = Parser->get_document();
// Set processing instruction for stylesheet
const xmlNodePtr PINode = xmlNewDocPI(
Doc->cobj(),
reinterpret_cast<xmlChar*>("xml-stylesheet"),
reinterpret_cast<xmlChar*>("href=\"../stylesheet.xslt\" type=\"text/xsl\"")
);
if (PINode != NULL) {
xmlAddPrevSibling(Doc->get_root_node()->cobj(), PINode);
}
Doc->write_to_file_formatted("mydoc.xml", "utf-8");
Upvotes: 3