Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

[XSLT Question] Having trouble to process the input conditionally...

Status
Not open for further replies.

werep

Vendor
Jun 5, 2005
4
US
Hi all, I have been trying to set up a XSLT script to process a XML input conditionally, and I am stuck...

I just need it to be able to process the XML input conditionally and return an output in XML format.

That is, within the XML input, there are multiple sets of node (I am always confused about how to describe them correctly...), and the script is going to check each set of node for a particular element (ex. a certain types of sport). If the node does contain a particular element, then certain elements of that node will be extract and output. Otherwise, that node will not be output at all.
--------
(input.xml)
Code:
<root_node>

- <member id="100">
  - <contact_info>
    - <name>
        <full_name>joe smith</full_name>
    + <address>
    + <phone>
    </contact_info>
  
  - <hobby num="0">
      <sport>baseball</sport>
    </hobby>

  - <hobby num="1">
      <sport>football</sport>
    </hobby>
  .
  .
  .
  + <hobby num="n">
  </member>

+ <member id="101">
+ <member id="102">
.
.
.
+ <member id="n">

</root_node>

(output.xml)
Code:
<root>
  - <member>
    .
    .
    . 
    (member 1's full name)
    (member 1's sport that matched the criteria)
    .
    .
    .
    </member>

  - <member>
    .
    .
    . 
    (member 1's full name)
    (member 1's sport that matched the criteria)
    .
    .
    .
    </member>
  .
  .
  .
  + <member num="n">
</root>
--------

I have tried to use <xsl:if> or <xsl:choose> to filter out just the wanted informations, but it didn't work the way I wanted.

One of the problems I have with the output, is that instead of output in the format that I mentioned above, it outputs like (assume there are three member nodes that contain a matched elements, and are being output):

(output)
Code:
- <member>

    <member 1's full name>some name</member 1's full name>
    <member 2's full name>some name</member 1's full name>
    <member 3's full name>some name</member 1's full name>
    <member 1's matched sport>some sport</member 1's matched sport>
    <member 2's matched sport>some sport</member 1's matched sport>
    <member 3's matched sport>some sport</member 1's matched sport>

 </member>

Can anyone give me an insight? (It doesn't have be an example script, just point out what kind of possible scripting error I might have that generates the above output)

Thank you.
 
I made a mistake in my above post and couldn't edit it:

(output.xml)
Code:
<root>
  - <member>
    .
    .
    . 
    (member 1's full name)
    (member 1's sport that matched the criteria)
    .
    .
    .
    </member>

  - <member>
    .
    .
    . 
    (member [COLOR=red][b]2[/b][/color]'s full name)
    (member [COLOR=red][b]2[/b][/color]'s sport that matched the criteria)
    .
    .
    .
    </member>
  .
  .
  .
  + <member num="n">
</root>
 
An important question to ask is what are you going to do with the output xml file? If you purely want to display the data, you don't need to create a second 'view' of the data.

However, if you do have a genuine need for a new structure you'll need to think about the best way to do it to get as much semantic information as you require for your ultimate goal. As your goal is not clear, I can't really give you a good answer, but this might be able to start you off:
Code:
<xsl:stylesheet xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL] version="1.0">
  <xsl:output method="xml"/>
  <xsl:variable name="filter">
    <sports>
      <sport>baseball</sport>
      <sport>football</sport>
    </sports>
  </xsl:variable>
  <xsl:template match="/">
    <members>
      <xsl:apply-templates select="root_node/member"/>
    </members>
  </xsl:template>
  <xsl:template match="member">
    <member>
      <xsl:copy-of select="contact_info/name/full_name"/>
      <xsl:for-each select="$filter/sports/sport">
        <xsl:copy-of select="hobby[sport = current()]"/>
      </xsl:for-each>
    </member>
  </xsl:template>
</xsl:stylesheet>

Jon

"There are 10 types of people in the world... those who understand binary and those who don't.
 
Jon, thank you very much for your reply.

As for the usages of the output XML file, for one, I want to use it to generate a summary page with a list of members that fit the criteria, such as a certain sports.

I don't quite understand what you mean by creating a second view of the data though, but as long as the XSL stylesheet can filter the data, and extract those that I need in a specific format, that will suit my needs very well.

What I did originally, was that I tried to setup one conditional check (using <xsl:if> or <xsl:choose>) to exam the content of the sport element, and all <xsl:apply-templates> of the desired output elements are inside that conditional statement, such as:

<xsl:if test="...">
<xsl:apply-templates>
<xsl:apply-templates>
<xsl:apply-templates>
</xsl:if>

But now it seems like that I did it so wrong.
-----------------------------

Jon, similar to my original question, but expanded a bit, is it possible that you can show me how to accomplish the following?

Let's say that the content of my input xml file is like the following (it should contain info of multiple member, but for simplicity, I just included one's):

input.xml
Code:
<?xml version="1.0" encoding="UTF-8" ?>

<MemberList>
  <Member id="NY-100">
    <ContactInfo>
      <Name>
        <FullName>joe smith</FullName>
      </Name>
      <Address1>1234 Sunset blvd</Address>
    </ContactInfo>

    <Sport num="0">
      <Type>football</Type> 
      <YearBeenPracticing>1</YearBeenPracticing> 
      <Skill-Level>2</Skill-Level> 
    </Sport>

    <Sport num="1">
      <Type>swimming</Type> 
      <YearBeenPracticing>3</YearBeenPracticing> 
      <Skill-Level>4</Skill-Level> 
    </Sport>
  </Member>
</MemberList>

If I want find out which member is interested in football or tennis, and then extract the following info of that member:
<FullName>
<Address>
<SportType> Only extract the matched one. So if the member has two other sports that don't match, those two won't be extracted
<YearBeenPracticing>

How should I modify the above script that you have written to do it?

I am very appreciate for your help.
 
Code:
<xsl:stylesheet xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL] version="1.0">
  <xsl:output method="xml"/>
  <xsl:variable name="filter">
    <sports>
      <sport>tennis</sport>
      <sport>football</sport>
    </sports>
  </xsl:variable>
  <xsl:template match="/">
    <members>
      <xsl:apply-templates select="MemberList/Member"/>
    </members>
  </xsl:template>
  <xsl:template match="Member">
    <member>
      <xsl:copy-of select="ContactInfo/Name/FullName"/>
      <xsl:copy-of select="ContactInfo/Address"/>
      <xsl:for-each select="$filter/sports/sport">
        <xsl:apply-templates select="Sport[Type = current()]"/>
      </xsl:for-each>
    </member>
  </xsl:template>
  <xsl:template match="Sport">
    <SportType>
      <xsl:value-of select="Type"/>
    </SportType>
    <xsl:copy-of select="YearBeenPracticing"/>
  </xsl:template>
</xsl:stylesheet>

Jon

"There are 10 types of people in the world... those who understand binary and those who don't.
 
Jon, thank you for the example script. Unfortunately, when I tried to use it to process the input XML file, the output that it generated didn't contain anything at all. It probably had to do with the function call part, and I didn't know how to work with that. (I am hoping to get the script to work without using a funcation call, because it's too advanced for my current level, even though it's more efficient)

Anyway, I made a XSL stylesheet using <xsl:choose> for filtering out the needed data and it seems to work OK for my needs. Yet, there are few parts that I wasn't able to solve them myself, and I really need some helps from the master.

1) Now my XSL stylesheet can output just those member(s) with the matched sport type(s), which is either baseball or football.

However, within the output, besides the matched sport type, the rest of the sport type are being output too.

For example, a certain member is participating in three sport types, and only one of those three is a matched one (either baseball or football that is), and I want just that one to be output. How should I do that?

2) For the XML output, I want to have an element called <schedule>, which its content is going to be the time of the event, such as:

<event>baseball</event> == <schedule>9am-12pm</schedule>
<event>football</event> == <schedule>1pm-3pm</schedule>

Thus, in the XML output I can have:

<Member>
.
.
.
<Sport>
.
.
.
<Type>baseball</Type>
.
.
.
<Schedule>9am-12pm</Schedule>
.
.
.
</Sport>
.
.
.
</Member>

Is that I should use either <xsl:variable> or <xsl:parameter> for such task? Can someone show me how I can implement to my existing XSL script?


Thanks in advance.
---------------

Updated input.xml
Code:
<?xml version="1.0" encoding="UTF-8" ?>

<MemberList>
  <Member id="NY-100">
    <ContactInfo>
      <Name>
        <FullName>joe smith</FullName>
      </Name>
      <Address>1234 Sunset blvd</Address>
    </ContactInfo>

    <Sport num="0">
      <Type>baseball</Type> 
      <YearBeenPracticing>8</YearBeenPracticing> 
      <Skill-Level>4</Skill-Level> 
    </Sport>

    <Sport num="1">
      <Type>hiking</Type> 
      <YearBeenPracticing>3</YearBeenPracticing> 
      <Skill-Level>5</Skill-Level> 
    </Sport>
    
    <Sport num="2">
      <Type>swimming</Type> 
      <YearBeenPracticing>16</YearBeenPracticing> 
      <Skill-Level>4</Skill-Level> 
    </Sport>
  </Member>
  
  <Member id="NY-101">
    <ContactInfo>
      <Name>
        <FullName>bob dole</FullName>
      </Name>
      <Address>834 Senior Way</Address>
    </ContactInfo>

    <Sport num="0">
      <Type>tennis</Type> 
      <YearBeenPracticing>10</YearBeenPracticing> 
      <Skill-Level>3</Skill-Level> 
    </Sport>

    <Sport num="1">
      <Type>smoking</Type> 
      <YearBeenPracticing>30</YearBeenPracticing> 
      <Skill-Level>5</Skill-Level> 
    </Sport>
  </Member>
</MemberList>

Updated xsl.xsl
Code:
<xsl:stylesheet 
  xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL]
  version="1.0" >
 
 
  <xsl:template match="/">
    <xsl:element name="Members">
     
      <!--<xsl:for-each select="/MemberList/Member/Sport[Type='football']">-->
        
        <xsl:apply-templates select="MemberList/Member"/>
        
      <!--</xsl:for-each>-->
      
    </xsl:element>
  </xsl:template>
  
  <xsl:template match="Member">
    <Member>
      <xsl:choose>
        <xsl:when test="Sport[Type='baseball' or 'football']">
      
        <xsl:copy-of select="ContactInfo/Name/FullName" />
        <xsl:copy-of select="ContactInfo/Address" />
        <xsl:element name="Sport">
          <xsl:apply-templates select="Sport"/>
        </xsl:element>
    
        </xsl:when>
      </xsl:choose>
    </Member>
  </xsl:template>
  
  <xsl:template match="Sport">
    <xsl:choose>
      <xsl:when test="//Type/. ='baseball' or 'football' ">
      
        <xsl:element name="Year-Been-Practicing">
          <xsl:value-of select="YearBeenPracticing" />
        </xsl:element>
        <xsl:element name="Skill-Level">
          <xsl:value-of select="Skill-Level" />
        </xsl:element>
    
      </xsl:when>
    </xsl:choose>
    
  </xsl:template>
 
</xsl:stylesheet>
 
One way to do it:
Code:
<?xml version="1.0"?>
<xsl:stylesheet 
  xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL] 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
      exclude-result-prefixes="msxsl"
        version="1.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:variable name="times">
    <baseball>9am-12pm</baseball>
    <football>1pm-3pm</football>
  </xsl:variable>
  <xsl:template match="/">
    <Members>
      <xsl:apply-templates select="MemberList/Member"/>
    </Members>
  </xsl:template>
  
  <xsl:template match="Member">
    <Member>
      <xsl:copy-of select="ContactInfo/Name/FullName"/>
      <xsl:copy-of select="ContactInfo/Address"/>
      <xsl:apply-templates select="Sport[Type='baseball' or Type='football']"/>
    </Member>
  </xsl:template>
  
  <xsl:template match="Sport">
    <Sport>
      <xsl:copy-of select="*"/>
      <Schedule>
        <xsl:value-of select="msxsl:node-set($times)/*[name(.) = current()/Type]"/>
      </Schedule>
    </Sport>
  </xsl:template>
</xsl:stylesheet>
What end result are you trying to achieve? A web page?

Jon

"Asteroids do not concern me, Admiral. I want that ship, not excuses.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top