Avatar of chenegar
chenegar
 asked on

XSLT Exclude Empty Elements

I'm a rank amateur when it comes to XSLT. I have a stylesheet that works except that I need to exclude empty elements. It's a long stylesheet, so here is an abbreviated version.
<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:strip-space elements="*"/>
  <xsl:output method = "xml" indent = "yes" />

  <!--
  This is a transform to create an XML file from the ANX file output by the Debt Collection HotDocs intake.
  -->
  
  <xsl:template match="/AnswerSet"> 

	<xsl:element name="OnlineIntake">
.
.
.
                 <xsl:for-each select="//Answer[@name='Factor']/RptValue/MCValue">

			<xsl:variable name="getfactors" select="position()"/>

			<xsl:element name="Factors">			
				<xsl:element name="Factor">					
						<xsl:value-of select="//Answer[@name='Factor']//MCValue[$getfactors]"/>		
				</xsl:element>			
				<xsl:element name="FactorAmt">
					<xsl:value-of select="//Answer[@name='FactorAmount']//NumValue[$getfactors]"/>
				</xsl:element>				
			</xsl:element>  <!-- Factors -->		
		</xsl:for-each> <!-- end of foreach for Factors -->

Open in new window


The input looks like this
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AnswerSet title="" version="1.1">
	<Answer name="(ANSWER FILE HISTORY)">
		<TextValue>Debt Collection Intake : May 6, 2015, 15:15
Maintenance Interview : February 18, 2015, 15:34
</TextValue>
.
.
.
<Answer name="Factor">
		<RptValue>
			<MCValue>
				<SelValue>Child Care/Work-Related</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Current income taxes</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Mortgage payments</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Rent</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Transportation Expenses/Work-Related</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Tools &amp; Equipment/Work-Related</SelValue>
			</MCValue>
			<MCValue unans="true"/>
		</RptValue>
	</Answer>
<Answer name="Factor">
		<RptValue>
			<MCValue>
				<SelValue>Child Care/Work-Related</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Current income taxes</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Mortgage payments</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Rent</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Transportation Expenses/Work-Related</SelValue>
			</MCValue>
			<MCValue>
				<SelValue>Tools &amp; Equipment/Work-Related</SelValue>
			</MCValue>
			<MCValue unans="true"/>
		</RptValue>
</AnswerSet>

Open in new window

And the output looks like this
<Factors>
    <Factor>Child Care/Work-Related</Factor>
    <FactorAmt>100.0000000</FactorAmt>
  </Factors>
  <Factors>
    <Factor>Current income taxes</Factor>
    <FactorAmt>250.0000000</FactorAmt>
  </Factors>
  <Factors>
    <Factor>Mortgage payments</Factor>
    <FactorAmt>600.0000000</FactorAmt>
  </Factors>
  <Factors>
    <Factor>Rent</Factor>
    <FactorAmt>0.0000000</FactorAmt>
  </Factors>
  <Factors>
    <Factor>Transportation Expenses/Work-Related</Factor>
    <FactorAmt>100.0000000</FactorAmt>
  </Factors>
  <Factors>
    <Factor>Tools &amp; Equipment/Work-Related</Factor>
    <FactorAmt>75.0000000</FactorAmt>
  </Factors>
  <Factors>
    <Factor/>
    <FactorAmt/>
  </Factors>

Open in new window

The output should not have the last empty <Factors> elements. Everything I've tried so far either crashes the transform or skips the Factors output. I can't change the input file, so can one of you experts help?
XML

Avatar of undefined
Last Comment
Gertone (Geert Bormans)

8/22/2022 - Mon
ASKER CERTIFIED SOLUTION
Gertone (Geert Bormans)

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Gertone (Geert Bormans)

The short answer is... add a simple xsl:if before you output the element to the result tree

But I saw some other ways of improvement
jumping up the tree and come back to basically the same element node is expensive
Your source XML had obvious errors because you cut away some stuff,
but basically I think you need to add brackets and positional predicates at the right place to address the correct node

And I restructured a bit... you should use apply-templates over for-each whenever possible (and that means almost always :-)
chenegar

ASKER
Thank you, Geert. I knew I needed to use apply-template but I couldn't figure out how to write it. And I love the simplicity of your answer! I inherited the transform and I plan to re-write all of it when I get a chance because I know it's kind of kludgy.

The code you gave me works for getting all the Factors but it's only picking up the first FactorAmt. I've been trying to understand the code you wrote but I can't figure out what I need to add to get all the FactorAmts.
chenegar

ASKER
Ah, I've got it! I made one change in your code and I got all of the factors and their amounts. Your code was
<xsl:variable name="amt" select="(//Answer[@name='FactorAmount'])[$getfactors]//NumValue"></xsl:variable>

Open in new window

And I changed it to
<xsl:variable name="amt" select="(//Answer[@name='FactorAmount'])//NumValue[$getfactors]"></xsl:variable>

Open in new window


Thanks so much for your help!
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
Gertone (Geert Bormans)

welcome,
I just got back so I only saw your feedback now.
I would have asked a proper source to evaluate, because that XPath depends really on the structure of the source XML. Glad you found it yourself
cheers