2

Is it possible to transform an attribute from "book1chapter2" into "chapter2" ?

For example this node:

<a myAttribute="part1chapter2" />

Should be transform into

<a myAttribute="chapter2" />

I tried:

<xsl:variable name="chapter" select="replace('part1chapter2', 'book1', '')" />

But it results in an compile error:

ERROR:  'Error checking type of the expression 'funcall(replace, [literal-expr(part1chapter2), literal-expr(part1), literal-expr()])'.'
FATAL ERROR:  'Could not compile stylesheet'

I use XSLT version 2.0.

A solution without any library would be appreciate :)

EDIT:

Java code, compile and run with javac -g TestXslt.java; java TestXslt;

public static void main(String[] args) throws IOException, URISyntaxException, TransformerException {
    TransformerFactory factory = TransformerFactory.newInstance();
    Source xslt = new StreamSource(new File("../transform.xslt"));
    Transformer transformer = factory.newTransformer(xslt);

    Source text = new StreamSource(new File("../input.xml"));
    String r = new String();
    StreamResult result = new StreamResult(new File("../output.xml"));
    transformer.transform(text, result);
}

Java version javac 1.6.0_27

Charles
  • 11,367
  • 10
  • 77
  • 114
  • What stylesheet compiler are you using? It might not be fully XSLT 2.0 compatible... Have a look at [this question](http://stackoverflow.com/questions/3067113/xslt-string-replace) for an XSLT 1.0 specific answer. – Mihai Todor Mar 01 '13 at 10:48
  • I would like a XSLT 2.0 solution. – Charles Mar 01 '13 at 10:57
  • Adding an upvote because I think the downvotes are totally unreasonable. – Michael Kay Mar 01 '13 at 11:28
  • 1
    The default XSLT processor for provided JDK version is `1.0`! Though it doesn't explain why "substring-after()" function errored out.. still worth giving try to different XSLT processor (like SAXON).. – Rookie Programmer Aravind Mar 01 '13 at 11:39

3 Answers3

7

I think that you imagine that saying version="2.0" on your stylesheet will automatically get you an XSLT 2.0 processor. That's not the way it works. The processor you get is determined by what's on your classpath, and if you pick up the default JDK processor, it only supports XSLT 1.0. The spec for XSLT 1.0 says that if it sees a call to an unrecognized function like replace(), it should raise a run-time error.

To run this under XSLT 2.0, download Saxon and ensure it is on your classpath. Ideally, for robustness, don't rely on the JAXP loading method to find it, but load it explicitly. Instead of

TransformerFactory factory = TransformerFactory.newInstance();

do

TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl();
Rich
  • 15,602
  • 15
  • 79
  • 126
Michael Kay
  • 156,231
  • 11
  • 92
  • 164
1

I'm not quite sure whether you're trying to change the attribute contents or the attribute name.

If the former, the replace function parameters are (input-string, regex, replacement-string), so you could try something like replace(@attributeToChange, 'book1chaper2', 'book1'). If the latter, then I think you need something like:

<xsl:attribute name="book1">
    <xsl:value-of select="@book1chaper2"/>
</xsl:attribute>

EDIT

It's odd that you're getting a compiler error though. If there's a problem with that function in your XSLT engine, another approach (if you're changing the contents) would be:

<xsl:choose>
    <xsl:when test="@attributeToChange='book1chaper2'">
         <xsl:text>book1</xsl:text>
    </xsl:when>
    <xsl:otherwise>
         <xsl:value-of select="@attributeToChange"/>
    </xsl:otherwise>
</xsl:choose>

FURTHER EDIT

Sounds like your processor is perhaps XSLT 1.0:

Error when running XSLT with eclipse

Try using starts-with(@attributeToChange, 'book1') as a test in a choose-when-otherwise.

Community
  • 1
  • 1
Giles
  • 1,331
  • 1
  • 15
  • 30
  • I can't test test="@attributeToChange='book1chaper2'" because I don't know "chaper2". – Charles Mar 01 '13 at 11:03
  • How about `starts-with(@attributeToChange, 'book1')`. I'm not quite sure of all your conditions. – Giles Mar 01 '13 at 11:07
  • Are you sure your processor supports XSLT 2.0? – Giles Mar 01 '13 at 11:09
  • Here is my stylesheet tag: . – Charles Mar 01 '13 at 11:18
  • 1
    Try checking that your classpath includes the necessary XSLT JAR – Giles Mar 01 '13 at 11:21
  • I think the Transformer is for XLST 1.0: http://docs.oracle.com/javase/6/docs/api/javax/xml/transform/TransformerFactory.html#newTemplates(javax.xml.transform.Source) – Charles Mar 01 '13 at 11:22
  • Your stylesheet is marked as being version 2, but that doesn't necessarily mean the processor you're using can support it. However, I think your issue may just be classpath related. – Giles Mar 01 '13 at 11:23
0

You could simply do this:

<xsl:variable name="chapter" select="substring-after('book1chapter2', 'book1', '')" />

But will the value always contain "book1" at the beginning? Are you getting the "book1" value from somewhere else and therefore will always know what part to remove?

JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • Yes I'm sure that book1 is always there. I try substring-after but the results was: ERROR: 'Error checking type of the expression 'funcall(substring-after, [literal-expr(part1chapter2), literal-expr(part1), literal-expr()])'.' – Charles Mar 01 '13 at 11:01
  • @charles, then problem isn't with version of XSLT, it is with XSLT processor.. Coz substring-after() is present in XSLT 1.0 as well.. which IDE are you using? if it is Eclipse then go for XALAN PE, which uses XSLT 2.0 .. – Rookie Programmer Aravind Mar 01 '13 at 11:07
  • I'm not using any IDE, I use sublime. Compile and run are done with command line. I will edit my question with java code. – Charles Mar 01 '13 at 11:10