2

This is presumably an almost carbon copy of Using XSLT as an XML pre-processor But as the OP of that question did not post a full example, despite being asked to, the replies are no use to anyone not familiar with XSLT. Neither have extensive web searches turned up anything helpful - XSLT seems remarkably poorly documented and little discussed on the Web.

Anyway ...

I have an XML file, say foo.xml, as follows (greatly simplified, obviously):

 <?xml version="1.0" encoding="UTF-8"?>

 <main>

  <fee>blah</fee>

  <ifdef select="OLD_VERSION">
   <fi>blah blah</fi>
  </ifdef>

  </main>

(C-style #ifdef changed to "ifdef" block in light of Ian Roberts's answer)

I want to run an xsltproc command on linux, as follows:

xsltproc --stringparam xmlver NEW_VERSION --nonet foo.xslt foo.xml

and have this use the following XSLT file, foo.xslt, to exclude the #ifdef'ed section:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output method="xml" />
 <xsl:param name="xmlver" required="yes"/>

 <xsl:template match="node() | @*">
  <xsl:copy><xsl:apply-templates select="node() | @*"/></xsl:copy>
 </xsl:template>

 <xsl:variable name="defines" select="document($xmlver)/defines"/>

 <xsl:template match="ifdef">

  <xsl:variable name="this" select="."/>

  <xsl:for-each select="$defines[def = $this/@select]">
   <xsl:apply-templates select="$this/node()" />
  </xsl:for-each>

 </xsl:template>

</xsl:stylesheet>

(I did use the replies to the question referenced above to construct this XSLT; but the missing ingredient is where/how to incorporate the "xmlver" value. Of course there is no guarantee it is correct in the above; but this essentially what I am asking - How is all this put together in a way that works?)

Any constructive replies will be greatly appreciated, and will doubtless be useful to many people with a similar requirement in the future; but please no tiresome, dogmatic "Why would you want to do that?" replies!

Community
  • 1
  • 1
John R Ramsden
  • 355
  • 4
  • 14

3 Answers3

1

The question you refer to looks like it's based on an XML structure that uses XML elements for its ifdefs. In your case your #ifdef lines are not XML elements, so you can't match them with an XSLT template. You'd be better off using a non-XML tool (possibly even the normal C pre-processor) to handle the ifdefs and feed the resulting XML to an XSLT if you need to do other XML-aware processing on it.

If you're happy to use real XML elements for your ifdefs, as in the previous question:

<?xml version="1.0" encoding="UTF-8"?>
<main>
  <fee>blah</fee>

  <ifdef select="OLD_VERSION">
   <fi>blah blah</fi>
  </ifdef>

</main>

then the question becomes how to treat the xmlver command line parameter as the single ifdef that you want to include, rather than as the location of a file from which to load a whole set of defines (which is how the previous question worked). That is much simpler:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output method="xml" />
 <xsl:param name="xmlver" />

 <xsl:template match="node() | @*">
  <xsl:copy><xsl:apply-templates select="node() | @*"/></xsl:copy>
 </xsl:template>

 <xsl:template match="ifdef">
 <!-- for the ifdef we want, include all its child elements, text nodes etc
      but not its attributes, for other ifdefs do nothing -->    
  <xsl:if test="@select = $xmlver">
   <xsl:apply-templates select="node()" />
  </xsl:if>
 </xsl:template>

</xsl:stylesheet>

My previous attempt at this used a <xsl:template match="ifdef[@select=$xmlver]">, which works in some processors but not in xsltproc (it is technically not allowed by the XSLT spec, and xsltproc is stricter than my usual test harness, Xalan).

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Many thanks for your prompt reply, Ian I tried cpp [ http://gcc.gnu.org/onlinedocs/cpp/ ], which would have been the easiest option certainly; but unfortunately it compresses multiple spaces, and could make far worse unintended changes or fail entirely if it encountered C-like syntax! I'm happy to change the ifdefs to XML-style blocks as you suggest. So granted that, the question becomes how are "select" and/or "OLD_VERSION" used in the XSLT file to filter the blocks? – John R Ramsden Sep 05 '12 at 14:08
  • `required="yes"` is syntactically illegal in XSLT 1.0. – Dimitre Novatchev Sep 05 '12 at 14:32
  • One has to single-quote $xmlver, to avoid an XPath error, i.e. after the first comment: – John R Ramsden Sep 05 '12 at 15:33
  • Hmm, I've updated my answer again. I wasn't aware of this before, but it turns out the XSLT spec doesn't allow variable references in template `match` expressions. Quoting the var won't help as then it'll be trying to match exactly the string `$xmlver`, not the value of the parameter. – Ian Roberts Sep 05 '12 at 16:10
  • Many thanks again Ian - I've been struggling with this for the last half an hour ;-) – John R Ramsden Sep 05 '12 at 16:17
  • Ian: XSLT2.0 does allow variables in match expressions. One 'gotcha' with the 'if' though, is that now any `ifdef` elements that do NOT meet that test are discarded, instead of being handled by the identity template. That may not be relevant in this case, but it's something to be aware of generally. – Flynn1179 Sep 05 '12 at 17:23
  • @Flynn1179 yes, in this case that was the point. My previous version also had an `` – Ian Roberts Sep 05 '12 at 17:30
1

suggestion: instead of xsltproc, can you just use m4 ?

<?xml version="1.0" encoding="UTF-8"?>

 <main>

  <fee>blah</fee>

ifdef(`X',`
   <fi>blah blah</fi>
')

</main>

.

$ m4 jeter.xml
<?xml version="1.0" encoding="UTF-8"?>

 <main>

  <fee>blah</fee>



</main>

.

$ m4 -DX jeter.xml
<?xml version="1.0" encoding="UTF-8"?>

 <main>

  <fee>blah</fee>


   <fi>blah blah</fi>


</main>
Pierre
  • 34,472
  • 31
  • 113
  • 192
  • Thanks, that looks good in theory; but sadly m4 apparently doesn't support UTF-8. Also, wouldn't one need fiddly amendments for quotes occurring in the enclosed block. (My XML actually contains far more than "blah blah" ;-) A "here document" syntax for blocks would be very helpful, but I didn't see any reference to that in the documentation. – John R Ramsden Sep 05 '12 at 14:45
  • I would have voted this up, as it is useful to know and you provided simple examples; but I'm a few rep points short of upvoting privilege! – John R Ramsden Sep 08 '12 at 08:12
0

I'd like to start with your general approach:

the replies are no use to anyone not familiar with XSLT. Neither have extensive web searches turned up anything helpful - XSLT seems remarkably poorly documented and little discussed on the Web.

This basically tells us that you are trying to write a program in a language you are not familiar with, and that you are trying to find information about that language by googling for it. Is that a good learning strategy?

I would have thought your problem was too many hits rather than too few, for example "XSLT tutorial" gives 2,300,000 hits. The top ones are all well worth a read. It seems odd to describe that as "poorly documented and little discussed".

Personally though if I'm going to start programming in a new language I always start by reading a book on the subject. Online material is rarely as carefully designed, written and reviewed as a text book. Of course I would say that since I'm the author of one of the most popular XSLT reference books, but I think it's true nonetheless.

Now, can I help you with your problem. Not really, I regret. Some people respond to questions on this forum with working tested code that you can use without understanding it. I don't: I simply point people in the right direction; and I'm not going to give you fragments of code in a language you don't understand. Pointing you in the right direction in this case means telling you to learn the language before you try using it.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Of course you're right about the need for systematic study before using a language extensively, to get the best out of it and not be constantly stumped! But this was a one-off requirement. Also, I learned a lot by getting stuck in and struggling with a specific task (although Ian Roberts did most of the work ;-), and in my experience anything studied, but not used, soon fades from the memory - "Use it or lose it" as the saying goes. – John R Ramsden Sep 08 '12 at 08:05