How can I not include empty elements?

View: New views
6 Messages — Rating Filter:   Alert me  

How can I not include empty elements?

by jlr :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I have an XML document that will display the elements as shown below.
Basically, the elements are a subset of the <row> tag.  The elements
will always have the tag names of column1, column2, column3, and column4.
As shown in the example below, some of the tag names column1, etc. may
have elements, and some of the tag names for column1, etc. may be empty
elements.  I have only given one listing of empty elements, but this could be up to
50 empty elements.  When creating the PDF document in xslt, is there a way of  removing
the empty elements so that they won't display?
I have the xslt code after the xml detail.

Thanks in advance for any comments.
jlr

XML DETAIL ***************************************************
     <row>        
           <column1>
              1
           </column1>      
           <column2>
              233
           </column2>        
           <column3>
              ea
           </column3>      
           <column4>
              this is a bigg statement within the document I am just adding some numbers and calculations
           </column4>    
       </row>
       <row>
           <column1>
               2
           </column1>      
           <column2>
               333
           </column2>        
           <column3>
               ea
           </column3>      
           <column4>
              fds fds fds fd fds fds fds fds fds fds fds fds fds fds fds fds
           </column4>    
       </row>
       <row>    
          <column1>
            3
         </column1>      
         <column2>
             6
         </column2>        
         <column3>
             ea
         </column3>      
         <column4>
            dsffsdiowkledsjknlefdsihjbwqjkb ysf uhfehufeuhfeuhfe
         </column4>            
       </row>
       <row>
          <column1>
           
         </column1>      
         <column2>
           
         </column2>        
         <column3>
           
         </column3>      
         <column4>
           
         </column4>    
       </row>  

XSLT CODE:********************************************************

  <fo:block  text-align="left">
          <fo:table table-layout="fixed" >                                          
          <fo:table-column column-width="15mm"/>
          <fo:table-column column-width="20mm"/>
          <fo:table-column column-width="14mm"/>
          <fo:table-column column-width="50mm"/>      

          <fo:table-body>
              <xsl:for-each select="header/row">    
                     
                  <fo:table-row border-after-style="double" >                  
                     <fo:table-cell  xsl:use-attribute-sets="cell-padding"  border="solid black 0.5px" >                      
                       <fo:block xsl:use-attribute-sets="detailtablecenter">                                  
                            <xsl:value-of select="column1"/>
                       </fo:block>      
                    </fo:table-cell>
                    <fo:table-cell  xsl:use-attribute-sets="cell-padding"  border="solid black 0.5px" >        
                       <fo:block xsl:use-attribute-sets="detailtablecenter">          
                         <xsl:value-of select="column2"/>
                       </fo:block>                
                    </fo:table-cell>

                    <fo:table-cell xsl:use-attribute-sets="cell-padding" border="solid black 0.5px" >                                        
                       <fo:block xsl:use-attribute-sets="detailtablecenter">        
                         <xsl:value-of select="column3"/>
                        </fo:block>  
                    </fo:table-cell>


                <fo:table-cell xsl:use-attribute-sets="cell-padding" border="solid black 0.5px" >                        
                        <fo:block xsl:use-attribute-sets="detailtableleft">        
                           <xsl:value-of select="column4"/>
                         </fo:block>                                                    
                   </fo:table-cell>                                        
             </fo:table-row>                
            </xsl:for-each>
          </fo:table-body>
        </fo:table>
     </fo:block>        

Re: How can I not include empty elements?

by Mark Lundquist-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



On May 14, 2008, at 5:50 AM, jlr wrote:

> I have an XML document that will display the elements as shown below.
> Basically, the elements are a subset of the <row> tag.  The elements
> will always have the tag names of column1, column2, column3, and  
> column4.
> As shown in the example below, some of the tag names column1, etc. may
> have elements, and some of the tag names for column1, etc. may be  
> empty
> elements.  I have only given one listing of empty elements, but this  
> could
> be up to
> 50 empty elements.  When creating the PDF document in xslt, is there  
> a way
> of  removing
> the empty elements so that they won't display?
> I have the xslt code after the xml detail.

Okay, first of all you should be doing this, e.g.:

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

instead of

        <xsl:value-of select="column1"/>

Once you have fixed that, then just add this template:

        <xsl:template match="row/*[not (normalize-space (.))]"/> <!-- kill  
empty columns -->


HTH,
—ml—



Re: How can I not include empty elements?

by Tony Graham-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Wed, May 14 2008 13:50:02 +0100, jean.stachler@... wrote:

> I have an XML document that will display the elements as shown below.
> Basically, the elements are a subset of the <row> tag.  The elements
> will always have the tag names of column1, column2, column3, and column4.
> As shown in the example below, some of the tag names column1, etc. may
> have elements, and some of the tag names for column1, etc. may be empty
> elements.  I have only given one listing of empty elements, but this could
> be up to
> 50 empty elements.  When creating the PDF document in xslt, is there a way
> of  removing
> the empty elements so that they won't display?
> I have the xslt code after the xml detail.

YMMV, but you could try <fo:table-cell empty-cells="hide"> [1] which, if
implemented by your processor, should mean that empty cells don't have
any borders and entirely empty rows don't appear at all.

If you want to omit empty rows (and empty-cells="hide" doesn't work for
you), you could change:

>               <xsl:for-each select="header/row">    

to:

  <xsl:for-each select="header/row[normalize-space()]">

along the lines of the post by Mark Lundquist.

If you went from a "pull" style of selecting what to process to a "push"
style of the document structure determining which template rule is used
then you could go to something like:

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

  <xsl:output method="xml"/>

  <xsl:template match="/">
    <fo:block  text-align="left">
      <fo:table table-layout="fixed" >
        <fo:table-column column-width="15mm"/>
        <fo:table-column column-width="20mm"/>
        <fo:table-column column-width="14mm"/>
        <fo:table-column column-width="50mm"/>

        <fo:table-body>
          <xsl:apply-templates/>
        </fo:table-body>
      </fo:table>
    </fo:block>
  </xsl:template>

  <xsl:template match="row">
    <fo:table-row border-after-style="double" >
      <fo:table-cell  xsl:use-attribute-sets="cell-padding"
        border="solid black 0.5px" >
        <fo:block xsl:use-attribute-sets="detailtablecenter">
          <xsl:value-of select="column1"/>
        </fo:block>
      </fo:table-cell>

      <fo:table-cell  xsl:use-attribute-sets="cell-padding"
        border="solid black 0.5px" >
        <fo:block xsl:use-attribute-sets="detailtablecenter">
          <xsl:value-of select="column2"/>
        </fo:block>
      </fo:table-cell>

      <fo:table-cell xsl:use-attribute-sets="cell-padding"
        border="solid black 0.5px" >
        <fo:block xsl:use-attribute-sets="detailtablecenter">
          <xsl:value-of select="column3"/>
        </fo:block>
      </fo:table-cell>

      <fo:table-cell xsl:use-attribute-sets="cell-padding"
        border="solid black 0.5px" >
        <fo:block xsl:use-attribute-sets="detailtableleft">
          <xsl:value-of select="column4"/>
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </xsl:template>

  <xsl:template match="row[not(normalize-space())]"/>

</xsl:stylesheet>
----------------------------------------------------------------------

As always, there's many ways to slice and dice the problem.  One of
several ways to also reduce the repetition of the fo:table-cell elements
is using a lookup for attribute values that can differ, e.g.:

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

  <xsl:output method="xml"/>

  <crown:align name="column1">center</crown:align>
  <crown:align name="column2">center</crown:align>
  <crown:align name="column3">center</crown:align>
  <crown:align name="column4">left</crown:align>

  <xsl:attribute-set name="detailtablealign">
    <xsl:attribute name="text-align">
      <xsl:value-of
        select="document('')/*/crown:align[@name=local-name(current())]"/>
      <!-- Define other common attributes here. -->
    </xsl:attribute>
  </xsl:attribute-set>

  <xsl:template match="/">
    <fo:block  text-align="left">
      <fo:table table-layout="fixed" >
        <fo:table-column column-width="15mm"/>
        <fo:table-column column-width="20mm"/>
        <fo:table-column column-width="14mm"/>
        <fo:table-column column-width="50mm"/>

        <fo:table-body>
          <xsl:apply-templates/>
        </fo:table-body>
      </fo:table>
    </fo:block>
  </xsl:template>

  <xsl:template match="row">
      <fo:table-row border-after-style="double" >
        <xsl:apply-templates/>
      </fo:table-row>
  </xsl:template>

  <xsl:template match="row[not(normalize-space())]"/>

  <xsl:template match="column1 | column2 | column3 | column4">
    <fo:table-cell xsl:use-attribute-sets="cell-padding"
      border="solid black 0.5px" >
      <fo:block xsl:use-attribute-sets="detailtablealign">
        <xsl:apply-templates/>
      </fo:block>
    </fo:table-cell>
  </xsl:template>
</xsl:stylesheet>
------------------------------------------------------------

Regards,


Tony Graham                         Tony.Graham@...
Director                                  W3C XSL FO SG Invited Expert
Menteith Consulting Ltd
XML, XSL and XSLT consulting, programming and training
Registered Office: 13 Kelly's Bay Beach, Skerries, Co. Dublin, Ireland
Registered in Ireland - No. 428599   http://www.menteithconsulting.com
  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
xmlroff XSL Formatter                               http://xmlroff.org
xslide Emacs mode                  http://www.menteith.com/wiki/xslide
Unicode: A Primer                               urn:isbn:0-7645-4625-2


[1] http://www.w3.org/TR/xsl11/#empty-cells


Parent Message unknown Re: How can I not include empty elements?

by David Arakelian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


You can also do something like this. Forgive me for not using your code,
but I think it would be easier due to its length:

** XML **

<artists>
        <artist>Fela Anikulapo Kuti</artist>
        <artist>Gaspar Lawal</artist>
        <artist></artist>
</artists>

<xsl:for-each select="//artits/artist[text()]">
        <td><xsl:value-of select="." />
</xsl:for-each>

The text() function just selects any node that has text content. I'm not
sure if it will work for whitespace. You can find reference on the XPath
functions here: http://saxon.sourceforge.net/saxon6.5.3/expressions.html

Although I think its rather slim and incomplete.

--
      ,'/:.          David Arakelian
    ,'-/::::.        http://www.theatons.com/
  ,'--/::(@)::.      Web Security Consultant
,'---/::::::::::.    Wales
____/:::::::::::::.  
  T H E A T O N S  



Parent Message unknown Re: How can I not include empty elements?

by Լեւոն Մկրտչյան :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


In reply to David A's comments, he has made a slight mistake in his reply when he says the text() function returns nodes that have text. This function will actually return to text node. You would probably want to do something like this:

<xsl:for-each select="//artits/artist">
        <xsl:if test="text()">
                <td><xsl:value-of select="node()" /></td>
        </xsl:if>
</xsl:for-each>
 
           .-.                    
                .-'``(|||)                                     Լեւոն Մկրտչյան
      ,`     `-`.                http://altjira.co.uk/
     /    '``-.   `
   .-.  ,       `___:
  (:::) :        ___
   `-`  `       ,   :
        / ,..-`   ,
      `./ /    .-.`
         `-..-(   )
               `-`




Re: How can I not include empty elements?

by Tony Graham-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Mon, May 19 2008 00:15:34 +0100, levon@... wrote:
> In reply to David A's comments, he has made a slight mistake in his
> reply when he says the text() function returns nodes that have
> text. This function will actually return to text node. You would

We are straying from jlr's original post, but David's example was:

   <xsl:for-each select="//artits/artist[text()]">

and his description was "The text() function just selects any node that
has text content."

Strictly speaking, text() is a node test [1], not a function.  The XPath
1.0 definition is:

   The node test text() is true for any text node. For example,
   child::text() will select the text node children of the context node.

The use of text() in '[text()]' means the predicate [2] filters what
would otherwise be selected so that it includes only nodes that have
text node children (since '[text()]' is abbreviated syntax [3] for
'[child::text()]').

So if I were to describe David's select expression*, I'd say the
expression selects only artist elements that have text node children.

Regards,


Tony Graham                         Tony.Graham@...
Director                                  W3C XSL FO SG Invited Expert
Menteith Consulting Ltd
XML, XSL and XSLT consulting, programming and training
Registered Office: 13 Kelly's Bay Beach, Skerries, Co. Dublin, Ireland
Registered in Ireland - No. 428599   http://www.menteithconsulting.com
  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
xmlroff XSL Formatter                               http://xmlroff.org
xslide Emacs mode                  http://www.menteith.com/wiki/xslide
Unicode: A Primer                               urn:isbn:0-7645-4625-2


*  W.r.t. the provided XML and after fixing typos in the XSLT

[1] http://www.w3.org/TR/xpath#node-tests
[2] http://www.w3.org/TR/xpath#predicates
[3] http://www.w3.org/TR/xpath#path-abbrev