views:

293

answers:

2

I have a set of XML files that I am processing with an XSL transform. They have a default namespace, so my XSL transform must contain the declaration:

xpath-default-namespace="urn:CZ-RVV-IS-VaV-XML-NS:data-1.2.2"

The problem is that this value changes from time to time, and my transform suddenly stops working, until I look at an example from the new file, extract this namespace ID and put it in the transform, whereby the transform stops working for old files. Is there a way to pass this as a parameter, or set it somehow at runtime? I have tried the parameter syntaxes that I looked up in various tutorials, but none have worked for this particular use.

I have searched all sorts of forums and found references to namespace-agnostic coding of XSL, but not figured out how to do it. Ian Williams' book "XSLT and Xpath" states that the default namespace must be declared, or you get nothing in the output stream, which is how it has worked for me. But I really don't want to have to change this by hand regularly, I want to give the user something that will work, without needing constant attention from me.

The only 100% reliable way I have invented so far is to use a standard programming language to open both the XML source and XSL transform as text files, extract the URI from the XML source, paste it into the XSL transform, close both files and then, finally run the actual transform. This works, but is incredibly dorky, at least to my taste. How can I better deal with changing default namespaces?

Pete

A: 

Have you tried defining a stylesheet parameter <xsl:param name="xpdn"/> and using it in the stylesheet declaration or top level template declaration as in

<xsl:template match="...." xpath-default-namespace="$xpdn">

I can't find anything in the spec that says this won't work (but I'm not in a position to try it just now).

Jim Garrison
That would work only if the attribute's value was an expression (e.g., as with "select" in <xsl:value-of select="$xpdn"/>). But the spec says it's a URI, not an expression. Some non-expression attributes can be dynamic, using an attribute value template (AVT) using curly quotes, as in <xsl:element name="{$n}">, but xpath-default-namespace isn't one of those attributes.
Evan Lenz
Ah, I see. Thanks for the clarification.
Jim Garrison
+1  A: 

The value of xpath-default-namespace must be a static URI, so you'll have to pre-process the stylesheet if you want it to vary. One way to do that would be to use XSLT. Apply the following meta-stylesheet to your primary stylesheet each time, and then invoke the pre-processed result instead.

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

  <!-- Pass in the new namespace URI as a stylesheet parameter -->
  <xsl:param name="new-uri" required="yes"/>

  <!-- By default, copy everything as is -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- But update the value of @xpath-default-namespace -->
  <xsl:template match="@xpath-default-namespace">
    <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
      <xsl:value-of select="$new-uri"/>
    </xsl:attribute>
  </xsl:template>

</xsl:stylesheet>

This is a bit of a strange use case though, because namespaces weren't really designed to be so dynamic. They were designed to qualify names, i.e. make up part of a name. When you look at it that way, dynamic namespaces don't make a lot of sense. Imagine a database whose table and field names arbitrarily changed every once in a while, forcing you to rewrite all your SQL scripts to keep up with the changes. That's what this is akin to.

Evan Lenz
Hello Evan,thanks, that does indeed fix my transform. I'm trying to modify it now, so that it reads the URI directly from the source XML file and updates the transform. I'm using AltovaXML2010 through MSWord VBA to run this whole thing, since the final output is an HTML bibliography document, which I load into Word as the last step. I don't know if their toolkit allows parameters to XSL files - if so, they've hidden it well. If I can get it working by simply running two transforms in a row, that would be simplest.
Pete Danes
I agree about the namespaces, but the authors of the XML files use that as a sort of version control and there isn't anything I can do about it. That's the way the sofware that generates the XML files works, they release a new version every year and each version has something like this "urn:CZ-RVV-IS-VaV-XML-NS:data-1.2.2" as the namespace ID. Last year it ended in "...1.2.1", this year it's "...1.2.2", no idea what will be next year. It's a government project, with all the intractability that is normal for such things. All I can do is design to accomodate it, as best I can. Pete
Pete Danes