Using
tag within XML for XSLT

2019-07-13 18:43发布

I am currently running into some trouble with an XML/XLST to HTML conversion I am working on. In short, I want to use <br /> tags within an XML tag, so that the HTML file after transformation will display a line break. After some tries I got that to work, however at the cost of some other functionallity. Namely the abillity to highlight parts.

First the dumped down XML file. So basically, there are several possible tags which all contain a first and last name. In this case I want the first and last name to be parsed on a seperate line (hence the <br /> tag). Furthermore in some instances a first or last name will need to be highlighted. In this case on line 3, last name "The Hand".

<swift_native>
<tag tag_code=":1:"><![CDATA[Jaco<br />Ronnie]]></tag>
<tag tag_code=":2:"><![CDATA[John<br />Doe]]></tag>
<tag tag_code=":2:"><![CDATA[Robbie<br />]]><highlight>The Hand</highlight></tag>
</swift_native>

So far, depending on the method I use within the XLST I either am able to get the linebreaks correct or the highlighting. But not both: The following figure shows this.

output Below you see the used XLST file. Where you can see that using <xsl:apply-templates/> will make the highlighting work and <xsl:value-of select="." disable-output-escaping="yes"/> will let me use the <br /> correctly.

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- HTML Layout definition -->
<xsl:output method="html"/>
<xsl:template match="swift_native">

    <html>
        <head>
            <title>
                <xsl:apply-templates select="message_id"/>
            </title>
            <style type="text/css">
                #tbl1,#tbl2 {display:none;}
                #lnk1,#lnk2   {border:none;background:none;width:85px;}
                td {FONT-SIZE: 75%; MARGIN: 0px; COLOR: #000000;}
                td {FONT-FAMILY: verdana,helvetica,arial,sans-serif}
                a {TEXT-DECORATION: none;}
                table.subtable {border-collapse:collapse;}
                table.subtable td {border:1px solid black;}
            </style>
        </head>
        <body>
            <table cellpadding="3" width="100%" class="subtable">
                <tr bgcolor="#cccccc">
                    <td colspan="3">Block4</td>
                </tr>
                <xsl:apply-templates select="tag" />
            </table>
        </body>
    </html>
</xsl:template>

<!-- Variable definition -->

<xsl:template match="tag">
    <tr>
        <td>
            <b>
                <xsl:value-of select="@tag_code" />
            </b>
        </td>
        <td>
            <xsl:value-of select="." disable-output-escaping="yes"/>
        </td>
        <td>
            <xsl:apply-templates/>
        </td>
    </tr>
</xsl:template>

<xsl:template match="highlight">
    <span style="background-color:yellow;">
        <xsl:apply-templates/>
    </span>
</xsl:template>

</xsl:stylesheet>

Obviously, the question is: does someone know a way in which I can use both the <br /> tag as the highlighting?

4条回答
Explosion°爆炸
2楼-- · 2019-07-13 18:46

One solution here is to use both:

<xsl:template match="tag">
    <tr>
        <td>
            <b>
                <xsl:value-of select="@tag_code" />
            </b>
        </td>
        <td>
            <xsl:apply-templates/>
        </td>
    </tr>
</xsl:template>

<xsl:template match="tag//text()">
    <xsl:value-of select="." disable-output-escaping="yes" />
</xsl:template>

<xsl:template match="highlight">
    <span style="background-color:yellow;">
        <xsl:apply-templates />
    </span>
</xsl:template>

Note however that if you do this, you need to ensure that any text values within the <tag> nodes are properly escaped in the CDATA, and doubly escaped outside it, that is, rather than

<tag tag_code=":2:"><![CDATA[Robbie & Bobbie <br />]]><highlight> &amp; The Hand</highlight></tag>

You would need to have:

<tag tag_code=":2:"><![CDATA[Robbie &amp; Bobbie<br />]]><highlight> &amp;amp; The Hand</highlight></tag>

So this is probably not a great approach if the <tag> elements have any possibility of containing XML special characters.

If you can ensure that the text directly below the <tag> will always be in a CDATA and that anything in lower nodes (e.g. <highlight>s) won't, then it's mildly simpler. You can replace the text matching template above with this one:

<xsl:template match="tag/text()">
    <xsl:value-of select="." disable-output-escaping="yes" />
</xsl:template>

And then you just need to ensure that the stuff in the CDATA is properly escaped, and that anything else is just valid XML.

Finally, if you have some control over your source data, you should consider abandoning the CDATA and just having the <br /> right in the <tag>:

<tag tag_code=":2:">Robbie<br /><highlight>The Hand</highlight></tag>

Then you could use this XSL, which is much more robust than anything that uses disable-output-escaping:

<xsl:template match="tag">
    <tr>
        <td>
            <b>
                <xsl:value-of select="@tag_code" />
            </b>
        </td>
        <td>
            <xsl:apply-templates/>
        </td>
    </tr>
</xsl:template>

<xsl:template match="tag/@* | tag/node()">
   <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
   </xsl:copy>
</xsl:template>

<xsl:template match="highlight">
    <span style="background-color:yellow;">
        <xsl:apply-templates />
    </span>
</xsl:template>
查看更多
Emotional °昔
3楼-- · 2019-07-13 18:56

Simple

in html is :

</br>

in XLS is :

<br></br>
查看更多
欢心
4楼-- · 2019-07-13 19:03

Happily, there's a simple solution too. Just add this line to yous xls:

<xsl:template match="br"><br/></xsl:template>  

This way, there's no need to wrap the data into CDATA, but instead use the much more intuitive

<tag tag_code=":1:">Jaco<br/>Ronnie</tag>

Likewise other common simple html tags may be included. Here's an example linking bold, italic, etc. to cs-styles, but a one-liner for each (like above) does work too:

<xsl:template match="i|b|u|strong">
    <span>
        <xsl:attribute name="class">html_<xsl:value-of select="name(.)" /></xsl:attribute>
        <xsl:apply-templates />
    </span>
</xsl:template>

If you find yourself doing this often, copy 'm all to html.xsl and use xsl:include to use them when needed.

查看更多
家丑人穷心不美
5楼-- · 2019-07-13 19:10

CDATA is telling the processor to interpret the contents as plain text, not markup. That's why disable-output-escaping is needed to prevent the <br/> from showing up as &lt;br/&gt;.

If you want to take advantage of disable-output-escaping, you'll have to break up the way that you select against the tag content.

Add a template

<xsl:template match="tag/text()">
    <xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:template>

and change the value-of line to

<xsl:apply-templates select="text()|*"/>
查看更多
登录 后发表回答