Feature Request - Extension to infer where namespace declarations exist / return node-set

Topics: Developer Forum, XPathmania
Jan 28, 2008 at 9:53 AM
I have written a stylesheet which converts xml to rtf - by this I mean, I make element names bold, highlight attribute values in blue.... The idea being that I provide a graphical UI for editing xml documents and xsl stylesheets - There is a good reason for this - it would take a while to explain the scenario in use.

The problem is: let's say you want to view and edit an xsl stylesheet in rtf.
How does one infer the namespace declarations in the xsl stylesheet and where within the xml document they reside? Also, what if I want to output the inner xml of a node as unencoded (xsl extension)?

Is this possible with Mvp.Xml?
Are there extension functions that exist to enable one to iterate all namespace declarations on an element node?
Can one return a node-set from an extension function via Mvp.Xml using .Net 2.0? (doesn't seem possible as System.Xml.XPath.XPathArrayIterator is no longer exposed).

Below is my stylesheet - the comments labelled TODO are where the hacks/assumptions reside....

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="no" omit-xml-declaration="no" />

<!-- Only copy the nodes that can be customised. -->
<xsl:template match="node()">

<xsl:if test="count(ancestor::*) = 0 and not(comment())">
<xsl:text disable-output-escaping="yes">{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}&#xA;</xsl:text>
<xsl:text disable-output-escaping="yes">{\colortbl ;\red128\green0\blue128;\red0\green0\blue0;\red0\green0\blue255;}&#xA;</xsl:text>
<xsl:text disable-output-escaping="yes">\viewkind4\uc1\pard\lang2057\f0\fs17 </xsl:text>
<!-- TODO: hard coded xml declaration for time-being. Can't seem to find out what it is using xpath. -->
<xsl:text disable-output-escaping="yes">\b <?xml version="1.0" encoding="UTF-8"?>\b0</xsl:text>
</xsl:if>

<xsl:if test="string-length(name(.)) > 0">
<xsl:text disable-output-escaping="yes">\par</xsl:text>
</xsl:if>

<xsl:if test="string-length(name(.)) > 0">
<!-- Indent node. -->
<xsl:call-template name="indent">
<xsl:with-param name="depth" select="count(ancestor::*)"/>
</xsl:call-template>

<!-- output element start tag and formatted name. -->
<xsl:text disable-output-escaping="yes"><\cf1\b </xsl:text>
<xsl:value-of select="name(.)" />
<xsl:text disable-output-escaping="yes">\cf0\b0 </xsl:text>

<xsl:if test="@*">
<xsl:text disable-output-escaping="yes"> </xsl:text>
<xsl:apply-templates select="@*" />
</xsl:if>

<!-- TODO: can this be dealt with in code as an xsl extension function
if can't determine all namespace definitions using xpath. -->
<xsl:if test="count(ancestor::*) = 0 and local-name(.) = 'stylesheet'">
<!-- hard coded xml declaration for time-being. Can't seem to find out what it is using xpath. -->
<xsl:text disable-output-escaping="yes"> \cf2\b xmlns:xsl</xsl:text>
<xsl:text disable-output-escaping="yes">\cf0\b0 =\cf3\i "</xsl:text>
<xsl:text disable-output-escaping="yes">http://www.w3.org/1999/XSL/Transform</xsl:text>
<xsl:text disable-output-escaping="yes">\cf0\i0 "</xsl:text>

<xsl:text disable-output-escaping="yes"> \cf2\b xmlns:fo</xsl:text>
<xsl:text disable-output-escaping="yes">\cf0\b0 =\cf3\i "</xsl:text>
<xsl:text disable-output-escaping="yes">http://www.w3.org/1999/XSL/Format</xsl:text>
<xsl:text disable-output-escaping="yes">\cf0\i0 "</xsl:text>
</xsl:if>
</xsl:if>

<xsl:choose>
<!-- if there is a child node of the current node output it. -->
<xsl:when test="child::node()">
<!-- close the parent node. -->
<xsl:text disable-output-escaping="yes">></xsl:text>
<!-- output the inner text if there is any. -->
<xsl:choose>
<xsl:when test="text()">
<!-- output the text. -->
<xsl:value-of select="translate(normalize-space(text()),'&#x0D;&#x0A;&#x09;','')"/>
</xsl:when>
<xsl:otherwise>
<!-- output the child node. -->
<xsl:apply-templates select="child::node()" />
<!--- new line before we open the closing tag. -->
<xsl:text disable-output-escaping="yes">\par</xsl:text>
<!-- Indent node. -->
<xsl:call-template name="indent">
<xsl:with-param name="depth" select="count(ancestor::*)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
<!--- open the closing tag. -->
<xsl:if test="string-length(name(.)) > 0">
<xsl:text disable-output-escaping="yes"></\cf1\b </xsl:text>
<!--- output the closing tag name. -->
<xsl:value-of select="name(.)" />
<!--- close the closing tag. -->
<xsl:text disable-output-escaping="yes">\cf0\b0 ></xsl:text>
</xsl:if>
</xsl:when>
<xsl:when test="string-length(name(.)) > 0">
<xsl:text disable-output-escaping="yes">/></xsl:text>
</xsl:when>
</xsl:choose>
</xsl:template>

<xsl:template match="@*">
<xsl:text disable-output-escaping="yes">\cf2\b </xsl:text>
<xsl:value-of select="name(.)" />
<!-- TODO: check to see if node text contains apos, if so make attribute surrounding characters quotes and vice versa. -->
<xsl:text disable-output-escaping="yes">\cf0\b0 ="\cf3\i </xsl:text>
<xsl:value-of select="." />
<xsl:text disable-output-escaping="yes">\cf0\i0 " </xsl:text>
<xsl:if test="@*">
<xsl:text disable-output-escaping="yes"> </xsl:text>
<xsl:apply-templates select="@*" />
</xsl:if>
</xsl:template>

<xsl:template name="indent">
<xsl:param name="depth" />
<xsl:if test="not($depth = 0)">
<xsl:text disable-output-escaping="yes"> </xsl:text>
<xsl:text disable-output-escaping="yes"> </xsl:text>
<xsl:text disable-output-escaping="yes"> </xsl:text>
<xsl:text disable-output-escaping="yes"> </xsl:text>
<xsl:call-template name="indent">
<xsl:with-param name="depth" select="$depth -1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

Regards,
Rik