1
votes

I have an xml document (input file cannot be changed) which I need to transform with xsl to another xml. The input xsl have a CDATA as shown in following example structure:

<TestCaseElement>
    <Role>VP</Role>
    <Code>
        <Line>
            <![CDATA[<id>l1_SomeId1</id> <val1>l1_SomeVal1</val1> <val2>l1_SomeVal2</val2> <algo>l1_somealgo</algo>]]>
        </Line>
        <Line>
            <![CDATA[<id>l2_someid1</id> <val1>l2_SomeVal1<val1> <val2>l2_SomeVal2<val2> <algo>l2_somealgo</algo>]]>
        </Line>
    </Code>
<TestCaseElement>

The expected result is something like:

<Expected>
    <MEASV id="l1_SomeId1" val1="l1_SomeVal1" val2="l1_SomeVal2" algo="l1_somealgo">
    <MEASV id="l2_SomeId1" val1="l2_SomeVal1" val2="l2_SomeVal2" algo="l2_somealgo">
</Expected>

My Xslt looks like:

<Expected>
    <xsl:for-each select="TestCaseElement[(Role='VP')]/Code/Line">                      
        <xsl:for-each select="current()/*">
            <MEASV>
                <xsl:attribute name="{fn:local-name()}"><xsl:value-of select="current()"/></xsl:attribute>
            </MEASV>
        </xsl:for-each>                                     
    </xsl:for-each>
</Expected>

The problem is the xslt doesn't recognize the tags inside CDATA. How can I apply a sort of disable-output-escaping for for-each? Or any other method to solve this?

1
Which XSLT processor will you be using? - michael.hor257k
The processor is inside a program called "MBT Suite". But looking at the about page I found it says "Saxon-HE 9.5.1". I assume this is the XSLT processor. - Eduardo Ramírez Gómez
Check the Saxon documentation to see if parsing a string as XML is supported as an extension. Otherwise you'll need to do this in two passes, where the first one does DOE and saves the result to a file. - michael.hor257k
You are right seems that I need to do 2 passes, any example on how to do that? I already tried creating intermediary file. Problem is I cannot write and then read from that intermediate file (XTRE1500 error) in same transformation. - Eduardo Ramírez Gómez
You must do 2 transformations, using 2 stylesheets. Hopefully your application can automate this. -- The real problem here is your data source; if they wanted you to parse the data, they would not provide it as CDATA. - michael.hor257k

1 Answers

0
votes

Consider to use XSLT 3.0 (as supported by Saxon 9.8 and Altova XMLSpy/Raptor) and parse-xml-fragment():

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <Expected>
            <xsl:apply-templates select="TestCaseElement[(Role = 'VP')]/Code/Line"/>
        </Expected>
    </xsl:template>

    <xsl:template match="Line">
        <MEASV>
            <xsl:apply-templates select="parse-xml-fragment(.)/*"/>
        </MEASV>
    </xsl:template>

    <xsl:template match="*">
        <xsl:attribute name="{local-name()}" select="."/>
    </xsl:template>

</xsl:stylesheet>

Note that in your posted sample one escaped markup <![CDATA[<id>l2_someid1</id> <val1>l2_SomeVal1<val1> <val2>l2_SomeVal2<val2> <algo>l2_somealgo</algo>]]> contains malformed markup with val1 and val2 not being properly closed so above code would fail for that input or you would need to use try/catch to catch any parsing error:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:err="http://www.w3.org/2005/xqt-errors"
    exclude-result-prefixes="xs math err"
    version="3.0">

    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <Expected>
            <xsl:apply-templates select="TestCaseElement[(Role = 'VP')]/Code/Line"/>
        </Expected>
    </xsl:template>

    <xsl:template match="Line">
        <MEASV>
            <xsl:try>
                <xsl:apply-templates select="parse-xml-fragment(.)/*"/>
                <xsl:catch errors="err:FODC0006">
                    <xsl:message select="'Error parsing', ."/>
                </xsl:catch>
            </xsl:try>
        </MEASV>
    </xsl:template>

    <xsl:template match="*">
        <xsl:attribute name="{local-name()}" select="."/>
    </xsl:template>

</xsl:stylesheet>