Sumathi
Sumathi

Reputation: 83

XSLT - Move only specified content into node

My Input XML is like as,

<section counter="yes" level="2">
<title>Course of Illness Following Stroke(<link idref="c003_f001">Fig. 3.1</link>)</title>
<section counter="yes" level="3">

Output should be,

<section counter="yes" level="2">
<title>Course of Illness Following Stroke</title>
<para><link idref="c003_f001">(Fig. 3.1)</link></para>
<section counter="yes" level="3">

Whenever the link is appearing within 'title' with parenthesis'()' then it should be moved to next para. If 'para' is not appeared then we should create and move the entire 'link' with parenthesis'()'.

I have wrote the XSLT but it's not given the desired output.

 <xsl:template match="title/text()">
    <xsl:if test="matches(., '\(') and following::node()[self::link]">
        <para>
        <xsl:copy>                        
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
        </para>
    </xsl:if>  
    <xsl:if test="matches(., '\)') and following::node()[self::link]">
        <xsl:copy>                        
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:if>  
</xsl:template>

Could you please guide us to resolve this issue.

Upvotes: 1

Views: 59

Answers (1)

friedemann_bach
friedemann_bach

Reputation: 1458

It does not make much sense to use xsl:apply-templates within a template that matches a text node. (And another issue: You do not really require matches(), as you do not need a regular expression to search for single round brackets; instead, contains() would be sufficient.)

A procedure for your scenario could works like this: Look for title that contains link surrounded by brackets (combining *-sibling:: and substring-*()). You can do that completely with XPath. In matching elements you just recompose the title, starting with copying title and filling it with all text before (. It could be neccessary to adjust this, depending on the possible content of title: Maybe it can contain other elements preceding to link (let us know if that is the case). After that, just insert a copy of link into a para. And that's it.

<xsl:template
    match="title[link[ends-with(preceding-sibling::text(), '(') and starts-with(following-sibling::text(), ')')]]">
    <xsl:copy>
        <xsl:value-of select="substring-before(text()[1], '(')"/>
    </xsl:copy>
    <para>
        <!-- edit -->
        <!--<xsl:copy-of select="link"/>-->
        <xsl:apply-templates mode="parenthesize" select="link"/>
        <!-- end edit -->
    </para>
</xsl:template>

<!-- edit: new template -->
<xsl:template match="link" mode="parenthesize">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:text>(</xsl:text>
        <xsl:apply-templates/>
        <xsl:text>)</xsl:text>
    </xsl:copy>
</xsl:template>

PS. I assume that you use identity transform for all other elements.

Upvotes: 1

Related Questions