[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

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

Subject: RE: How to delete empty element tag from output XML?
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Fri, 27 Oct 2000 10:48:30 +0100
empty element tag
Guangzu,

>Thanks to Kay Michael and Jeni Tennison for your help. A general template is
>what I am looking for. I wrote a template, it's more like a C function
>except more awkward. Most of the codes is for print tag. I wish I can use
><xsl:element> to print the tag which is passed by parameter but don't know
>how to assign the parameter to the name of element.

With xsl:element, the @name attribute can take an attribute value template,
so you can give computed values to the name of the element if you wrap the
computed (part of) the name in {}s:

<xsl:element name="{$tag}">
  ...
</xsl:element>

You can do the same with attribute names as well.  Actually, I used this in
the template in my previous message:

<xsl:template match="*">
  <xsl:variable name="translation" select="..." />
  <xsl:variable name="default" select="..." />
  <xsl:choose>
    <xsl:when test="string(.)">
       <!-- element added with the name given by $translation variable -->
       <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>

If you apply this to your template, then you get:

<xsl:template name="empty_content">
	<xsl:with-param name="content" />
	<xsl:with-param name="tag" />
	<xsl:with-param name="default" />
	<xsl:if test="$content  !=''">
		<xsl:element name="{$tag}">
			<xsl:value-of select="$content" />
		</xsl:element>
	</xsl:if>
	<xsl:if test="$content = ''">
		<xsl:if test="$default != ''">
			<xsl:element name="{$tag}">
				<xsl:value-of select="$default" />
			</xsl:element>
		</xsl:if>
	</xsl:if>	
</xsl:template>

You can see that this is a lot cleaner than all those xsl:texts.  I don't
know what the xsl:with-params are doing there - they're illegal at that
point (they're designed for being with an xsl:call-template or an
xsl:apply-templates, to *pass* parameters).  You meant xsl:param:

<xsl:template name="empty_content">
	<xsl:param name="content" />
	<xsl:param name="tag" />
	<xsl:param name="default" />
	<xsl:if test="$content  !=''">
		<xsl:element name="{$tag}">
			<xsl:value-of select="$content" />
		</xsl:element>
	</xsl:if>
	<xsl:if test="$content = ''">
		<xsl:if test="$default != ''">
			<xsl:element name="{$tag}">
				<xsl:value-of select="$default" />
			</xsl:element>
		</xsl:if>
	</xsl:if>	
</xsl:template>

There are some other changes that you could make if you wanted to, and I'll
step through them so that you can see the alternatives.  When you have two
xsl:ifs that test mutually-exclusive conditions side by side (as you do
here), then you can turn it into an xsl:choose with an xsl:when and an
xsl:otherwise instead:

<xsl:template name="empty-content">
	<xsl:param name="content" />
	<xsl:param name="tag" />
	<xsl:param name="default" />
	<xsl:choose>
		<xsl:when test="$content != ''">
			<xsl:element name="{$tag}">
				<xsl:value-of select="$content" />
			</xsl:element>
		</xsl:when>
		<xsl:otherwise>
			<xsl:if test="$default != ''">
				<xsl:element name="{$tag}">
					<xsl:value-of select="$default" />
				</xsl:element>
			</xsl:if>
		</xsl:otherwise>	
	</xsl:choose>
</xsl:template>

When you have a xsl:otherwise with an xsl:if inside it as the only content,
then you can turn it into an xsl:when with the test from the xsl:if to give
the same effect:

<xsl:template name="empty-content">
	<xsl:param name="content" />
	<xsl:param name="tag" />
	<xsl:param name="default" />
	<xsl:choose>
		<xsl:when test="$content != ''">
			<xsl:element name="{$tag}">
				<xsl:value-of select="$content" />
			</xsl:element>
		</xsl:when>
		<xsl:when test="$default != ''">
			<xsl:element name="{$tag}">
				<xsl:value-of select="$default" />
			</xsl:element>
		</xsl:when>	
	</xsl:choose>
</xsl:template>

When you are testing whether a string ($content and $default are both
strings) has content or not, you can use the fact that strings are true()
if they have content, and false() if they don't.  So within a test (which
automatically interprets its contents as a boolean expression):

  $content != ''

is equivalent to simply:

  $content

And the template can alternatively be:

<xsl:template name="empty-content">
	<xsl:param name="content" />
	<xsl:param name="tag" />
	<xsl:param name="default" />
	<xsl:choose>
		<xsl:when test="$content">
			<xsl:element name="{$tag}">
				<xsl:value-of select="$content" />
			</xsl:element>
		</xsl:when>
		<xsl:when test="$default">
			<xsl:element name="{$tag}">
				<xsl:value-of select="$default" />
			</xsl:element>
		</xsl:when>	
	</xsl:choose>
</xsl:template>

When you're passing parameters that include things about the content or
name of a node, then you may as well change the template to a moded
template that matches that node, and work out the content/name within the
template.  This saves on xsl:with-params, which are very verbose:

<xsl:template match="people">
	<Star>
		<FirstName><xsl:value-of select="N1" /></FirstName>
		<LastName><xsl:value-of select="N2" /></LastName>
		<xsl:apply-templates select="N3" mode="empty_content">
			<xsl:with-param name="tag">MI</xsl:with-param>
			<xsl:with-param name="default">N/A</xsl:with-param>
		</xsl:call-template>
		<xsl:call-template select="Sex" mode="empty_content">
			<xsl:with-param name="tag">Gender</xsl:with-param>
			<xsl:with-param name="default"></xsl:with-param>
		</xsl:call-template>
	</Star>
</xsl:template>

<xsl:template match="*" mode="empty-content">
	<xsl:param name="tag" />
	<xsl:param name="default" />
	<xsl:choose>
		<xsl:when test="string(.)">
			<xsl:element name="{$tag}">
				<xsl:value-of select="." />
			</xsl:element>
		</xsl:when>
		<xsl:when test="not($default)">
			<xsl:element name="{$tag}">
				<xsl:value-of select="$default" />
			</xsl:element>
		</xsl:when>	
	</xsl:choose>
</xsl:template>

A final point - if you're worried about the formatting of your output, then
I suggest you use:

  <xsl:output indent="yes" />

near the top of your stylesheet.  This will make the XSLT processor indent
things sensibly for you.

Cheers,

Jeni

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


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


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.