Re: [xsl] Q: XSLT 1.0 output of namespace

Subject: Re: [xsl] Q: XSLT 1.0 output of namespace
From: Hermann Stamm-Wilbrandt <STAMMW@xxxxxxxxxx>
Date: Tue, 17 Aug 2010 14:17:45 +0200
Lars,

thanks for your reply.

I only focussed on the distinction between attribute and namespace nodes.
I did not test all the testcases -- I should have done.
Below you can find a working stylesheet and 6 testcase outputs.


> The test above tests the child axis, correct?
Yes.

> So it is not testing whether the current node is a node/pi/comment/text
> node, but whether the current node has such children. Right?
Correct, now "self::" is used, see below.

> ... more likely the intent was to
> test whether the current node is (not) an element or anything else
> besides an attribute or a namespace node?
Yes.

> Also, the above test seems redundant, since anything matched by
> "processing-instruction()|comment()|text()" will also be matched by
> "node()".
Correct.

In getting the whole solution to work some other issues arose.

The first was that "node()" predicate is true for all 6 different types:
comment, processing-instruction, text, element, attribute and namespace.

Then I realized the the really difficult part was to differentiate between
element, attribute and namespace! (the worst being the empty element)

In getting to the solution below I found that
  ". = ../namespace::*[name()]"
as "is-namespace()" test is even simpler than Michael's
  "count(. | ../@*) != count(../@*)".

Similarly ". = ../attribute::*[name()]" can be used as "is-attribute()".

So my first shot for "is-element()" (after ruling out text, pi and comment)
was this:
  "not(. = ../attribute::*[name()] | ../namespace::*[name()])"

But this was incorrect for a default namespace declaration!
Just adding "name() and ..." fixed this issue.


Find below a sample XML file, and the stylesheet "dynxp.xsl".
As you can see you can pass any XPath statement via --stringparam.
This XPath expression is evaluated by dyn:evaluate() just for demonstration
and testing purposes.
Each result gets output separately and in a readable way.


Just in case email scrambles below listings find dynxp.xsl here [1].
(xpath++ tool [2] does similar stuff)


$ cat d.xml
<?some-PI testing?>
<a>
 <!-- comment1 -->
 <b n1="urn:a1" xmlns:n1="urn:n1"/>
 <c>text1<d a2="a2" xmlns="urn:d"/></c>
</a>

$ xsltproc --stringparam xpathpar "//comment()" dynxp.xsl d.xml

-------------------------------------------------------------------------------
<!-- comment1 -->
$ xsltproc --stringparam xpathpar "//processing-instruction()" dynxp.xsl
d.xml

-------------------------------------------------------------------------------
<?some-PI testing?>
$ xsltproc --stringparam xpathpar "/a/c/text()" dynxp.xsl d.xml

-------------------------------------------------------------------------------
text1
$ xsltproc --stringparam xpathpar "/a/b" dynxp.xsl d.xml

-------------------------------------------------------------------------------
<b xmlns:n1="urn:n1" n1="urn:a1"/>
$ xsltproc --stringparam xpathpar "/a/c/*/namespace::*" dynxp.xsl d.xml

-------------------------------------------------------------------------------
xmlns:xml="http://www.w3.org/XML/1998/namespace";
-------------------------------------------------------------------------------
xmlns="urn:d"
$ xsltproc --stringparam xpathpar "//attribute::*" dynxp.xsl d.xml

-------------------------------------------------------------------------------
n1="urn:a1"
-------------------------------------------------------------------------------
a2="a2"
$
$ cat dynxp.xsl
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:dyn="http://exslt.org/dynamic";
>
  <xsl:output omit-xml-declaration="yes"/>

  <xsl:param name="xpathpar" select="'//*'" />


  <xsl:template match="/">
    <xsl:for-each select="dyn:evaluate($xpathpar)">
      <xsl:call-template name="doOutput"/>
    </xsl:for-each>
  </xsl:template>


  <xsl:template name="doOutput">
    <xsl:text>
-------------------------------------------------------------------------------
</xsl:text>
    <xsl:choose>
      <xsl:when
        test="self::comment() |
              self::processing-instruction() |
              self::text()">
        <xsl:copy-of select="."/>
      </xsl:when>
      <xsl:when
        test="name() and
              not(. = ../attribute::*[name()] | ../namespace::*[name()])">
        <xsl:copy-of select="."/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:if test="not(. = ../attribute::*[name()])">
          <xsl:text>xmlns</xsl:text>
          <xsl:if test="name()">:</xsl:if>
        </xsl:if>
        <xsl:value-of select="name()"/>
        <xsl:text>="</xsl:text>
        <xsl:value-of select="string()"/>
        <xsl:text>"</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>
$


[1]
http://stamm-wilbrandt.de/en/xsl-list/dynxp.xsl

[2]
https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14455521&#14488694


Mit besten Gruessen / Best wishes,

Hermann Stamm-Wilbrandt
Developer, XML Compiler, L3
WebSphere DataPower SOA Appliances
----------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschaeftsfuehrung: Dirk Wittkopp
Sitz der Gesellschaft: Boeblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294



From:       Lars Huttar <lars_huttar@xxxxxxx>
To:         xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Cc:         Hermann Stamm-Wilbrandt/Germany/IBM@IBMDE
Date:       08/16/2010 06:08 PM
Subject:    Re: [xsl] Q: XSLT 1.0 output of namespace



On 8/16/2010 7:35 AM, Hermann Stamm-Wilbrandt wrote:
> Hello,
>
> this is a pure XSLT 1.0 question.
>
> Below template does the (readable) output of the current node even for
> attribute and namespace nodes.
> In the spec the following is stated:
>   "There is no pattern that can match a namespace node, ...".
>
> So I tried it with negative matches for node, pi, comment and text.
> But now the differentiation between namespace node and attribute node
> ( for output of  xnlns:ns1="..." / xmlns="..." / attr="..." )
> seems a bit complex to me.
>
> Can this be simplified?
>
>
>   <xsl:template match="@*">
>     attribute
>   </xsl:template>
>
>   <xsl:template name="doOutput">
>     <xsl:choose>
>       <!-- attribute could be matched, namespace not - handle both -->
>       <xsl:when test="not(node()|processing-instruction()|comment()|text
> ())">
>

A question for my own edification....
The test above tests the child axis, correct?
So it is not testing whether the current node is a node/pi/comment/text
node, but whether the current node has such children. Right?
So an empty element would pass this not() test; in other words, an empty
element would be treated the same as an attribute or a namespace node.
It seems like that is not the intent... more likely the intent was to
test whether the current node is (not) an element or anything else
besides an attribute or a namespace node?

Also, the above test seems redundant, since anything matched by
"processing-instruction()|comment()|text()" will also be matched by
"node()".
I'm not saying this to be critical, but because I believe the OP is a
smart guy, and this area is a confusing one for me, I want to check my
own comprehension.

Thanks,
Lars

Current Thread