Charles
Charles

Reputation: 11778

xslt remove part of attribute

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

Upvotes: 2

Views: 6604

Answers (3)

Michael Kay
Michael Kay

Reputation: 163312

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();

Upvotes: 7

Giles
Giles

Reputation: 1424

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.

Upvotes: 1

JLRishe
JLRishe

Reputation: 101662

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?

Upvotes: 0

Related Questions