Neozaru
Neozaru

Reputation: 1130

XSLT and text formatting

I'm making an XSLT template in order to convert XML to LaTeX (then, HTML). I think XSLT wasn't made for that, but it works. My only problem is text formatting : If in some lines of text, I want to use bold or italic words, the syntax is "< i >< / i >" in HTML for example, but "\textit{}" in LaTeX.

One solution is to declare "i" as a template, but I don't know if I can apply it "automatically" for each encountred text block (I don't want to call it explicitly in all my templates)

Sorry, I'm a newbie in this technology, maybe very simple solution exists, but Google didn't help me this time.

Any suggestion will be appreciated.

EDIT : For example :

Xsl :

<xsl:template match="one">
<xsl:apply-templates select="two"/>
</xsl:template>

XML :

<one>
<two>Some text with <i>italic</i> words</two>
</one>

Desired output :

"Some text with \textit{italic} words"

And I don't want to do :

<xsl:apply-templates select="i"/>

in all my templates

So I'm looking for a way to apply "globally" the "i" template.

Upvotes: 1

Views: 6784

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

As simple as this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>
    
 <xsl:template match="i">
     <xsl:text>\textit{</xsl:text>
     <xsl:apply-templates/>
     <xsl:text>}</xsl:text>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<one>
    <two>Some text with <i>italic</i> words</two>
</one>

the wanted, correct result is produced:

Some text with \textit{italic} words

Explanation:

The XSLT processing model uses a number of built-in templates, using which a default processing of any XML document is provided, should the XSLT programmer not provide a template matching a specific node.

In particular, the built-in template for any element node, just issues <xsl:apply-templates/> so that templates are applied on all of its children.

The built-in template for any text node is to copy this text node to the output.

This means that we don't need to provide any template for a node, if it must do exactly what the corresponding built-in template does.

That leaves us only with an i element -- so we provide a template matching i -- it simply surrounds by "\textit{" and "}" the result of processing its children.

Do note:

It is entirely possible to express a complex transformation without ever specifying a single <xsl:apply-templates>, <xsl:call-template>, <xsl:for-each>, <xsl:choose>, <xsl:when>, <xsl:otherwise> and <xsl:if>.

This is called "push-style" as opposed by the "pull-style" where one or any of these instructions are extensively used.

The "push" style expresses the most declarative solution of a problem, while a "pull-style" transformation expresses a more "imperative" solution.

It is in the spirit of XSLT and recommended to always try to produce as much "push" code as possible.

Upvotes: 3

Jayson Lorenzen
Jayson Lorenzen

Reputation: 575

EDIT: I added a complete XSL now at the end, based on the OP's XML and XSL

This is just an assumption because---as pointed out by Dimitre in the comments---we cannot see your XSL, input or desired output exactly. However, you may want something like this.

<xsl:template match="//i">
   <xsl:text>\textit{</xsl:text>
   <xsl:apply-templates select="@*|node()"/>
   <xsl:text>}</xsl:text>
</xsl:template>


  <!-- or with namespace -->

<xsl:template match="//*[namespace-uri()='http://www.w3.org/1999/xhtml' and local-name()='i']">
   <xsl:text>\textit{</xsl:text>
   <xsl:apply-templates select="@*|node()"/>
   <xsl:text>}</xsl:text>
</xsl:template>



<!-- assumes there is a copy happening like: -->
<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

Adding a template like that into the XSL, should cause it to be executed for each found in the input.

The output (when put into an XSL that just copies an HTML document) looks like:

<!-- before -->
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>test</title>
  </head>
  <body>
    <p>
      <i>This is Only a Test</i>
    </p>
  </body>
</html>


<!-- after -->
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>test</title>
  </head>
  <body>
    <p>
      \textit{This is Only a Test}
    </p>
  </body>
</html>

If you give us more, I will update this to be more specific.

EDIT: a complete example based on the OP's code (that was finally provided)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/">
    <xsl:apply-templates select="one"/>
  </xsl:template>

  <xsl:template match="one">
    <xsl:apply-templates select="two"/>
  </xsl:template>

  <xsl:template match="//i">
    <xsl:text>\textit{</xsl:text>
    <xsl:apply-templates select="@*|node()"/>
    <xsl:text>}</xsl:text>
  </xsl:template>

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

</xsl:stylesheet>

Upvotes: 0

Related Questions