0
votes

I have a a sample xml like follows,

<doc>
    <para>AAAAA BBB<s/>CCC DDD<l/>EEEE<t/>FFFFF <style>GGGG</style>HHHHHH</para>
</doc>

using XSLT I have to transform this to same node tree but add a name attribute to <para> node named 'name' and it's value should be content text of the <para> element.

So the output should be look like,

<doc>
    <p name="AAAAA BBB CCC DDD EEEE FFFFF GGGG HHHHHH">AAAAA BBB<s/>CCC DDD<l/>EEEE<t/>FFFFF <style>GGGG</style>HHHHHH</p>
</doc>

As you can see in the output, all the text nodes should be copied to the name attribute value a and all inline elements (<s/>,<t/>,<l/>,<style>) has to be removed. and all <s/>, <t/>, <l/> has to be replaced with space.

I've written following xslt for this,

<xsl:template match="p">
        <p name="{abc:process-attr-text(child::node())}">
            <xsl:apply-templates/>
        </p>
    </xsl:template>

    <xsl:function name="abc:process-attr-text">
        <xsl:param name="node"/>

        <xsl:sequence select="$node/text()"/>
    </xsl:function>

it gives following output,

<doc>
    <p name="GGGG">AAAAA BBB<s/>CCC DDD<l/>EEEE<t/>FFFFF <style>GGGG</style> HHHHHH</p>
</doc>

how can I modify my function to get the correct result?

2

2 Answers

4
votes

This is slightly awkward, the obvious answer of just using <p name="{.}"> won't work because it would simply concatenate all the descendant text nodes, giving AAAAA BBBCCC DDDEEEEFFFFF GGGGHHHHHH

If you want to ensure there are spaces wherever there is an XML tag between adjacent text nodes then you need to be a bit more creative. Try

<p name="{normalize-space(string-join(descendant::text(), ' '))}">

This joins all the text nodes with an extra space between them, then the normalize will squash two adjacent spaces down to one.

1
votes

Why not simply:

<xsl:template match="para">
    <p name="{.}">
        <xsl:apply-templates/>
    </p>
</xsl:template>