4 Replies Latest reply: Jun 28, 2012 8:28 AM by pl_sequel RSS

    Preserving space between elements in xslt

    pl_sequel
      Running on 11gR1...

      Trying to run an xslt to output html... and the transformation strips out the space between my 2 elements...(space between John and Smith is removed)
      SELECT XMLSERIALIZE (
                CONTENT XMLTRANSFORM (
                           xmltype (
                              '<data><column name = "USER_FNAME">John</column><column name = "USER_LNAME">Smith</column></data>'),
                           xmltype (
                              '<?xml version="1.0" encoding="UTF-8"?>
      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="html"/>
      <xsl:template match="/">
      <html>
      <body>
      <p>
      Hello <xsl:value-of select="/data/column[@name=''USER_FNAME'']"/> <xsl:value-of select="/data/column[@name=''USER_LNAME'']"/></p>
      </body></html>
      </xsl:template>
      </xsl:stylesheet>')) AS CLOB)
        FROM DUAL;
      Outputs:
      <html><body><p>
      Hello JohnSmith</p></body></html>
      From what I have read, this is the standard behaviour... the only thing I could do to get this to work was to add an xsl:text with xml:space="preserve"
      SELECT XMLSERIALIZE (
                CONTENT XMLTRANSFORM (
                           xmltype (
                              '<data><column name = "USER_FNAME">John</column><column name = "USER_LNAME">Smith</column></data>'),
                           xmltype (
                              '<?xml version="1.0" encoding="UTF-8"?>
      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="html"/>
      <xsl:template match="/">
      <html>
      <body>
      <p>
      Hello <xsl:value-of select="/data/column[@name=''USER_FNAME'']"/><xsl:text xml:space="preserve"> </xsl:text><xsl:value-of select="/data/column[@name=''USER_LNAME'']"/></p>
      </body></html>
      </xsl:template>
      </xsl:stylesheet>')) AS CLOB)
        FROM DUAL;
      Part of the issue is I'm also generating the xslt from user-inputted template... user enters simple templating code, I run it through various regexes to generate an xslt.. then run the xslt on xml data.

      Example:
      <p>Hello {{USER_FNAME}} {{USER_LNAME}}</p>
      That snippet is entered by a user, and turned into the xslt listed above... It seems having to replace all whitespace with empty xsl:text elements a bit problematic...Wondering if there is a more elegant solution?

      Thanks for the help and advice!
        • 1. Re: Preserving space between elements in xslt
          odie_63
          You're right about whitespaces handling in the stylesheet itself. They're stripped off unless we use <xsl:text>.
          It seems having to replace all whitespace with empty xsl:text elements a bit problematic
          Maybe not.
          For example, you can apply another regexp to convert whitespace-only text nodes into <xsl:text> elements :
          SQL> select regexp_replace(
            2    '<p>Hello <xsl:value-of select="/data/column[@name=''USER_FNAME'']"/> <xsl:value-of select="/data/column[@name=''USER_LNAME'']"/></p>'
            3  , '>(\s+)&lt;'
            4  , '><xsl:text>\1</xsl:text>&lt;'
            5  )
            6  from dual;
          
          REGEXP_REPLACE('<P>HELLO<XSL:VALUE-OFSELECT="/DATA/COLUMN[@NAME=''USER_FNAME'']"/><XSL:VALUE-OFSELECT="/DATA/COLUMN[@NAM
          ------------------------------------------------------------------------------------------------------------------------
          <p>Hello <xsl:value-of select="/data/column[@name='USER_FNAME']"/><xsl:text> </xsl:text><xsl:value-of select="/data/colu
          mn[@name='USER_LNAME']"/></p>
          
          {code}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
          • 2. Re: Preserving space between elements in xslt
            Jason_(A_Non)
            Any way you can work in a concat() to ensure the space shows up?
            SELECT XMLSERIALIZE (
                      CONTENT XMLTRANSFORM (
                                 xmltype (
                                    '<data><column name = "USER_FNAME">John</column><column name = "USER_LNAME">Smith</column></data>'),
                                 xmltype (
                                    '<?xml version="1.0" encoding="UTF-8"?>
            <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:output method="html"/>
            <xsl:template match="/">
            <html>
            <body>
            <p>
            Hello <xsl:value-of select="concat(/data/column[@name=''USER_FNAME''],'' '',/data/column[@name=''USER_LNAME''])"/></p>
            </body></html>
            </xsl:template>
            </xsl:stylesheet>')) AS CLOB)
              FROM DUAL;
            
            <html><body><p>
            Hello John Smith</p></body></html>
            • 3. Re: Preserving space between elements in xslt
              odie_63
              Hi Jason,

              From what I've understood, the problem is not about correctly render a space in an XSLT-transformed document (there are multiple way to do that indeed), but rather about building the piece of XSL out of the user-defined template.
              OP is using a search and replace on custom tags in the template, so it's might get tricky on complex mixed contents.
              • 4. Re: Preserving space between elements in xslt
                pl_sequel
                Thanks Odie.... that's what I was thinking.. I'll have to experiment with it and see how it goes. This should work nicely though, since the only cases where I need xsl:text explicitly is for whitespace only nodes between two elements...

                >
                Any way you can work in a concat() to ensure the space shows up?


                Thanks for the tip.. But given the use cases... I can't predict where users will input tags, and their intent when doing so in its simplest form, I get the template tags, regex_replace them into xsl:value-of xslt code and go from there.

                The other thing I'll be doing that I haven't shown in the example, is wrap everything outside of the template tags in CDATA blocks... since users will be mixing in html tags with custom template tags etc...

                I'm sure I'll come across other issues...


                Thanks again