tags:

views:

4756

answers:

8

Hello, I need some help with XSLT syntax. Here is my scenario, I have an XML file that needs to be transformed in to a different look and feel of XML file, I have several sections where if particular node set don't contain any value the whole section shouldn't be processed.

Here is an example of XML:

<Dates>
    <Date>
     <VALUE1></VALUE1>
     <VALUE2></VALUE2>
     <VALUE3></VALUE3>
     <VALUE4></VALUE4>
     <VALUE5>3333</VALUE5>
    </Date>
    <Date>
     <VALUE1>AAAA</VALUE1>
     <VALUE2></VALUE2>
     <VALUE3>JJJJ</VALUE3>
     <VALUE4></VALUE4>
     <VALUE5>12345</VALUE5>
    </Date>
</Dates>

screenshot of xml

Here is my XSLT with the if statement that don't work right

<xsl:for-each select="Level1/Level2/Level3">
    <xsl:if test="@VALUE1!=''">                    
    <MyDates>             
      <value_1>
       <xsl:value-of select="VALUE1"/> 
      </value_1>
      <value_2>
       <xsl:value-of select="VALUE2"/> 
      </value_2>
      <value_3>
       <xsl:value-of select="VALUE3"/> 
      </value_3>
      <value_4>
       <xsl:value-of select="VALUE4"/> 
      </value_4>   
    </MyDates>
    </xsl:if> 
</xsl:for-each>

So as you can see I basically want all nodes (VALUE1, VALUE2, VALUE3, etc) to have values or else don't process and move on to the next section

(If you cannot see the XML come thought, I also made a screen shot)

A: 

View Screenshot

Alex
There is no link to the screenshot. You have to use the buttons on the editor toolbar to insert a hyperlink or use Markdown formatting described here: http://en.wikipedia.org/wiki/Markdown
0xA3
A: 

Divo, I have tried the following: but this doesn't detect for some reason when value exist

Alex
What have you tried? Did you also try the suggestion of Chris?
0xA3
+6  A: 

You are trying to match xml elements with names "Level1", "Level2", etc... that don't exist in the document. Then, you are looking for a VALUE1 attribute on the last element.

I think you want something like this:

<xsl:for-each select="Dates">
    <MyDates>
     <xsl:for-each select="Date">
     <xsl:if test="not(*[.=''])">
      <MyDate>
       <value_1>
        <xsl:value-of select="VALUE1"/> 
       </value_1>
       <value_2>
        <xsl:value-of select="VALUE2"/> 
       </value_2>
       <value_3>
        <xsl:value-of select="VALUE3"/> 
       </value_3>
       <value_4>
        <xsl:value-of select="VALUE4"/> 
       </value_4>               
      </MyDate>
     </xsl:if>
     </xsl:for-each>
    </MyDates>
</xsl:for-each>

This will add a new MyDate element as long as every value in the corresponding Date element is not empty.

What it does is

  1. Create a new MyDates element for each Dates element.
  2. Check each Date element. The * matches all children. [.=''] means "is empty". Finally, it wraps all that in a not. This means the if only passes if there is not any child that is empty.
  3. If it has no children that are empty, it creates a new MyDate element with a copy of each value.

You may also want to check the W3Schools XSL and XPath tutorials.

Chris Marasti-Georg
A: 
<xsl:template match="Level1/Level2/Level3[@VALUE2 != '' and @VALUE2 != '' and @VALUE3 != '']>
    <output/>
</xsl:template>

etc.

jlew
+1  A: 

The @ is redundant - it refers to XML attributes.

You are trying to test for an element so just drop the @.

In addition:

  • Level1/Level2/Level3 is wrong
  • You are testing for VALUE1 only but want to test for all values (which can be done with *)
pinto
+2  A: 

You have not defined well what does it mean for "a node to have value".

Most probably, you will consider an element, that has a white space-only text child, not to have value. In this case, below is one solution:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:template match="Date[not(*[not(normalize-space())])]">
       <xsl:copy-of select="."/>
     </xsl:template>

     <xsl:template match="text()"/>
</xsl:stylesheet>

This templete for a "Date" element will not be matched if the "Date" contained even one child element, that has no content or only white space.

When this transformation is applied on the following XML document:

<Dates>
    <Date>
     <VALUE1></VALUE1>
     <VALUE2>  </VALUE2>
     <VALUE3></VALUE3>
     <VALUE4></VALUE4>
     <VALUE5>3333</VALUE5>
    </Date>
    <Date>
     <VALUE1>AAAA</VALUE1>
     <VALUE2>1</VALUE2>
     <VALUE3>JJJJ</VALUE3>
     <VALUE4>1</VALUE4>
     <VALUE5>12345</VALUE5>
    </Date>
</Dates> 

The correct result is produced:

<Date>
    <VALUE1>AAAA</VALUE1>
    <VALUE2>1</VALUE2>
    <VALUE3>JJJJ</VALUE3>
    <VALUE4>1</VALUE4>
    <VALUE5>12345</VALUE5>
</Date>
Dimitre Novatchev
A: 
<xsl:for-each select="Level1/Level2/Level3">
<MyDates>
 <xsl:if test="VALUE1!=''">
  <value_1>
   <xsl:value-of select="VALUE1"/>
  </value_1>
 </xsl:if>
 <xsl:if test="VALUE2!=''">
  <value_2>
   <xsl:value-of select="VALUE2"/>
  </value_2>
 </xsl:if>
 <xsl:if test="VALUE3!=''">
  <value_3>
   <xsl:value-of select="VALUE3"/>
  </value_3>
 </xsl:if>
 <xsl:if test="VALUE4!=''">
  <value_4>
   <xsl:value-of select="VALUE4"/>
  </value_4>
 </xsl:if>
</MyDates>

Rashmi Pandit
A: 

I think you can do this also. Instead of checking a node. VALUE1/text() will check if the node has some text within. You might want to make sure that there is no white space for these. Also, you can see if the VALUE1 element has a child node.

<xsl:if test="VALUE1/text()">                    

</xsl:if>   

<xsl:if test="VALUE1/child::node()">                    

</xsl:if>  
AJ