This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

RE: How to delete empty element tag from output XML?


Guangzu,

>1). if <Sex> is empty as in Amy case, don't print <Gender /> 
>2). if <N3> is empty as in Tom case, I need a output <MI>N/A</MI>, i.e. a
>default of "N/A".
>3). the structure and tag of output different with input.
>As I mentioned before, the last thing I want to do is use <xsl:if> in XSLT
>stylesheet to compare every segment because it's too tedious given the fact
>I have numberous tags need to process.

The obvious thing to do is to use xsl:if and xsl:choose:

----
<xsl:template match="people">
   <xsl:if test="string(N1)">
      <FirstName><xsl:value-of select="N1" /></FirstName>
   </xsl:if>
   <xsl:if test="string(N2)">
      <LastName><xsl:value-of select="N2" /></LastName>
   </xsl:if>
   <MI>
     <xsl:choose>
        <xsl:when test="string(N3)"><xsl:value-of select="N3" /></xsl:when>
        <xsl:otherwise>N/A</xsl:otherwise>
     </xsl:choose>
   </MI>
   <xsl:if test="string(Sex)">
      <Gender><xsl:value-of select="Sex" /></Gender>
   </xsl:if>
</xsl:template>
----

This keeps the semantic information about (a) what element names translate
to and (b) what empty elements default to all within the template itself.
The alternative is to have a generic template that deals with all types of
elements:

----
<xsl:template match="*">
  <xsl:variable name="translation" select="..." />
  <xsl:variable name="default" select="..." />
  <xsl:choose>
    <xsl:when test="string(.)">
       <xsl:element name="{$translation}">
          <xsl:value-of select="." />
       </xsl:element>
    </xsl:when>
    <xsl:when test="string($default)">
       <xsl:element name="{$translation}">
          <xsl:value-of select="$default" />
       </xsl:element>
   </xsl:when>
  </xsl:choose>
</xsl:template>
----

With this kind of template, you need to put the semantic information about
how to do the translation and what the default value is somewhere else, and
then access that information to give the value of the $translation and the
$default variables within the template.

The easiest way to do this is to have a variable that contains that
information, encoded in XML:

<xsl:variable name="translations">
  <translate name="N1">FirstName</translate>
  <translate name="N2">LastName</translate>
  <translate name="N3" default="N/A">MI</translate>
  <translate name="Sex">Gender</translate>
</xsl:variable>

Under XSLT 1.1, or with one of the various node-set() extensions that are
available with most XSLT Processors, you can access this variable as a node
set.  For example, given an element as the current node and that you're
using Saxon as your processor, with the appropriate namespace declarations
at the top of your stylesheet, you can find its translation with the XPath:

  saxon:node-set($translations)/translate[@name = name(current())]

and find its default with the XPath:

  saxon:node-set($translations)/translate[@name = name(current())]/@default

These XPaths are the values for the variables near the top of the above
template:

  <xsl:variable name="translation"
select="saxon:node-set($translations)/translate[@name = name(current())]" />
  <xsl:variable name="default"
select="saxon:node-set($translations)/translate[@name =
name(current())]/@default" />

If you're not comfortable using variables as node sets, and want to stick
to XSLT 1.0 for whatever reason, you can still use the same construction,
but access it using the document() function:

  <xsl:variable name="translation"
select="document('')/*/xsl:variable[@name = 'translations']/translate[@name
= name(current())]" />
  <xsl:variable name="default" select="document('')/*/xsl:variable[@name =
'translations']/translate[@name = name(current())]/@default" />

An alternative, if you have a schema somewhere where the translations
and/or the default values for the new elements are kept, is to access the
schema using the document() function and pull out the information that you
need from it.

When elements retain their name, then it's easiest to use xsl:copy or
xsl:copy-of.  When they don't, and you have small numbers of elements,
xsl:if is still tedious, but probably less tedious that the method outlined
above.  With large numbers of elements, it becomes a lot easier to add:

  <translate name="N3" default="N/A">MI</translate>

than

   <MI>
     <xsl:choose>
        <xsl:when test="string(N3)"><xsl:value-of select="N3" /></xsl:when>
        <xsl:otherwise>N/A</xsl:otherwise>
     </xsl:choose>
   </MI>

I hope that this helps,

Jeni

Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]