renaming an element -- how to copy namespace nodes?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Adam Barr

    renaming an element -- how to copy namespace nodes?

    I have a tag foo that I want to copy unchanged when it is a subtag of
    bar, so I have a template (x is the namespace for the document):

    <xsl:template match="x:bar/x:foo">
    <xsl:copy>
    <xsl:apply-templates/>
    </xsl:copy>
    </xsl:template>

    BUT, I discovered that someone has been mis-speling foo as foop in the
    source files. So I add another template to fix this up:

    <xsl:template match="x:bar/x:foop">
    <foo>
    <xsl:apply-templates/>
    </foo>
    </xsl:template>

    The problem is that the output now has xmlns attributes added to the
    foo tag that I output. If the input spells "foo" correctly, matching
    the first template above, this doesn't happen.

    I read in the docs that <xsl:copy> copies the namespace nodes, and I
    surmise that the fact that this is not done when I specify the
    explicit "<foo>" output is the reason for the xmlns attributes showing
    up. However, I can't figure out how to copy the namespace nodes. I try
    things such as

    <xsl:for-each select="namespa ce::*">
    <xsl:copy/>
    </xsl:for-each>

    or

    <xsl:copy-of select="namespa ce::*"/>

    but nothing seems to work (and it's not clear where exactly to put
    these). Changing <foo> to <xsl:element name="foo"> doesn't help
    either.

    The actual xmlns attribute varies between Microsoft's .Net XSLT (which
    outputs xmlns="") and Xalan (which outputs xmlns:x="[the URI for x]"
    xmlns="[the URI for x]". But what I want is no xlmns attributes at
    all, as it appears when the "foo" tag is copied by <xsl:copy>. Can
    this be done?

    Thanks.


    - adam
  • Ben Edgington

    #2
    Re: renaming an element -- how to copy namespace nodes?

    adamba@gte.net (Adam Barr) writes:[color=blue]
    > I have a tag foo that I want to copy unchanged when it is a subtag of
    > bar, so I have a template (x is the namespace for the document):
    >
    > <xsl:template match="x:bar/x:foo">
    > <xsl:copy>
    > <xsl:apply-templates/>
    > </xsl:copy>
    > </xsl:template>
    >
    > BUT, I discovered that someone has been mis-speling foo as foop in the
    > source files. So I add another template to fix this up:
    >
    > <xsl:template match="x:bar/x:foop">
    > <foo>
    > <xsl:apply-templates/>
    > </foo>
    > </xsl:template>
    >
    > The problem is that the output now has xmlns attributes added to the
    > foo tag that I output. If the input spells "foo" correctly, matching
    > the first template above, this doesn't happen.[/color]
    <snip>

    I think you need to make the default output namespace the same as the
    x namespace here with a 'xmlns="..."' declaration in the
    <xsl:styleshe et/> element. This will result in the new <foo/>
    elements being created in the same output namespace, and thus they
    *shouldn't* have an extra namespace declaration.

    So, with this XML

    ----
    <test xmlns="http://example.com/foo">
    <bar>
    <foo>Wibble</foo>
    <foop>Wobble</foop>
    </bar>
    </test>
    ----

    and this XSLT

    ----
    <xsl:styleshe et version="1.0"
    xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
    xmlns:x="http://example.com/foo"
    xmlns="http://example.com/foo"[color=blue]
    >[/color]

    <xsl:template match="/">
    <output>
    <xsl:apply-templates/>
    </output>
    </xsl:template>

    <xsl:template match="x:bar/x:foo">
    <xsl:copy>
    <xsl:apply-templates/>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="x:bar/x:foop">
    <foo>
    <xsl:apply-templates/>
    </foo>
    </xsl:template>

    </xsl:stylesheet>
    ----

    I get

    ----
    <output xmlns="http://example.com/foo" xmlns:x="http://example.com/foo">
    <foo>Wibble</foo>
    <foo>Wobble</foo>
    </output>
    ----

    Fiddle around with the exclude-result-prefixes attribute if you want
    to omit the redundant xmlns:x declaration.

    --
    Ben Edgington
    Mail to the address above is discarded.
    Mail to ben at that address might be read.

    Comment

    • David Carlisle

      #3
      Re: renaming an element -- how to copy namespace nodes?


      <foo>

      generates a foo element in the default namespace at that point (in the stylesheet).
      If that isn't the namespace used in te hrest of your source document
      then the serialiser will inser a namespace decaration to make sure that
      foo stays in this namespace.

      If you want to generate a foo element in the namespace you have bound to
      x: then you could go

      <x:foo>

      or perhaps you would prefer

      <foo xmlns=" whatever you have bound to x">

      normally you'd put xmlns=" whatever you have bound to x" on the
      xsl:stylesheet element rather than on each literal result element, so it
      is in scope over the whole stylesheet.
      [color=blue]
      > but nothing seems to work[/color]
      both of those work, as in copy namespace nodes but probably have no
      effect on the serialised result. Namespace nodes don't affect the name
      of the element (which is a pair consisting of namespace uri and local
      name) so once you have generated an element in no-namespace adding
      namespace nodes never affects that element it might cause namespace
      declaarations to be generated, but the system must make sure that these
      don't change the namespace of the elements being serialised.
      Don't think of namespaces as a type of attribute, think of them as part
      of the element name. the fact that they get serialised using attribute
      syntax is just a historical quirk.

      David

      Comment

      • Richard Tobin

        #4
        Re: renaming an element -- how to copy namespace nodes?

        In article <ce782195.04101 11539.75de977d@ posting.google. com>,
        Adam Barr <adamba@gte.net > wrote:
        [color=blue]
        ><xsl:templat e match="x:bar/x:foo">
        > <xsl:copy>
        > <xsl:apply-templates/>
        > </xsl:copy>
        ></xsl:template>[/color]

        This will output a foo in the namespace x is bound to.
        [color=blue]
        ><xsl:templat e match="x:bar/x:foop">
        > <foo>
        > <xsl:apply-templates/>
        > </foo>
        ></xsl:template>[/color]

        This will output a foo in no namespace, unless you have a default
        namespace declaration in the stylesheet. You probably want:

        <xsl:template match="x:bar/x:foop">
        <x:foo>
        <xsl:apply-templates/>
        </x:foo>
        </xsl:template>

        -- Richard

        Comment

        • Adam Barr

          #5
          Re: renaming an element -- how to copy namespace nodes?

          David Carlisle <davidc@nag.co. uk> wrote in message news:<yg4acus5l f9.fsf@penguin. nag.co.uk>...[color=blue]
          > <foo>
          >
          > generates a foo element in the default namespace at that point (in the stylesheet).
          > If that isn't the namespace used in te hrest of your source document
          > then the serialiser will inser a namespace decaration to make sure that
          > foo stays in this namespace.
          >
          > If you want to generate a foo element in the namespace you have bound to
          > x: then you could go
          >
          > <x:foo>
          >
          > or perhaps you would prefer
          >
          > <foo xmlns=" whatever you have bound to x">
          >
          > normally you'd put xmlns=" whatever you have bound to x" on the
          > xsl:stylesheet element rather than on each literal result element, so it
          > is in scope over the whole stylesheet.
          >
          >
          > David[/color]


          Thank you! The xmlns= did the trick (actually I did an <xsl:element
          name="foo" xmlns="...">).

          The .Net XslTransform was happy with just that; I had to add an
          exclude-result-prefixes="x" to my <xsl:stylesheet > to get Xalan to
          stop emitting the xlmns= attribute (in one place anyway...there were
          actually several places I did this renaming, and they seem to behave
          slightly differently based on whether the action inside of the
          renaming <xsl:element> was an <xsl:apply-templates> or <xsl:value-of>.
          More XSLT mystery...)

          - adam

          Comment

          • Adam Barr

            #6
            Re: renaming an element -- how to copy namespace nodes?

            richard@cogsci. ed.ac.uk (Richard Tobin) wrote in message news:<ckgkru$1l ki$1@pc-news.cogsci.ed. ac.uk>...[color=blue]
            > In article <ce782195.04101 11539.75de977d@ posting.google. com>,
            > Adam Barr <adamba@gte.net > wrote:
            >[color=green]
            > ><xsl:templat e match="x:bar/x:foo">
            > > <xsl:copy>
            > > <xsl:apply-templates/>
            > > </xsl:copy>
            > ></xsl:template>[/color]
            >
            > This will output a foo in the namespace x is bound to.
            >[color=green]
            > ><xsl:templat e match="x:bar/x:foop">
            > > <foo>
            > > <xsl:apply-templates/>
            > > </foo>
            > ></xsl:template>[/color]
            >
            > This will output a foo in no namespace, unless you have a default
            > namespace declaration in the stylesheet. You probably want:
            >
            > <xsl:template match="x:bar/x:foop">
            > <x:foo>
            > <xsl:apply-templates/>
            > </x:foo>
            > </xsl:template>
            >
            > -- Richard[/color]



            I tried <x:foo> but then it output the "x:" also which I didn't want.
            The only reason I was using a namespace to begin with was because the
            input XML had an xmlns= attribute in it (and various web searching
            revealed the "x:" solution to that). Instead I did <xsl:element
            name="foo" xmlns="[what x is bound to]"> and that worked (see other
            post).

            Thanks.

            - adam

            Comment

            Working...