XML Tutorials
  Home arrow XML Tutorials arrow Page 4 - Querying XML: Use Cases
eWeek
Codewalker Forums 
  Tutorials  
Database Articles  
Miscellaneous  
Navigation Usability  
PEAR Articles  
Programming Basics  
Server Administration  
XML Tutorials  
  Reviews  
Database Book Reviews  
Linux Book Reviews  
Miscellaneous Reviews  
PHP Book Reviews  
PHP Software Reviews  
Server Admin Reviews  
SQL Tool Reviews  
  Code Gallery  
Content Management Code  
Contest Code  
Counters Code  
Database Code  
Date Time Code  
Discussion Board Code  
Email Code  
File Manipulation Code  
GUI Code  
Link Farm Code  
Miscellaneous Code  
Search Code  
Site Navigation Code  
User Management Code  
Forums Sitemap 
Dedicated Servers  
Download TestComplete 
IBM® developerWorks
Weekly Newsletter 
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
XML TUTORIALS

Querying XML: Use Cases
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 2
    2008-02-14

    Table of Contents:
  • Querying XML: Use Cases
  • Use case SGML: Standard Generalized Markup Language.
  • Use case PARTS: recursive parts explosion.
  • Use case REF: queries based on references.
  • Further Discussion of the W3C XML Query-Use Cases in XSLT

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    CIO Insight
     
    ADVERTISEMENT

    Route your faxes to your email inbox. Private, secure fax numbers available from CallWave. Choose your fax number.

    Querying XML: Use Cases - Use case REF: queries based on references.
    (Page 4 of 5 )



    References are an important aspect of XML. This use case describes a database in which references play a significant role and contains several representative queries that exploit these references.

    Suppose that the file census.xml contains an element for each person recorded in a recent census. For each person element, the person’s name, job, and spouse (if any) are recorded as attributes. Thespouseattribute is an IDREF-type attribute that matches the spouse element’s ID-typenameattribute.

    The parent-child relationship among persons is recorded by containment in the element hierarchy. In other words, the element that represents a child is contained within the element that represents the child’s father or mother. Due to deaths, divorces, and remarriages, a child might be recorded under either its father or mother (but not both). In this exercise, the term “children of X” includes “children of the spouse of X.” For example, if Joe and Martha are spouses, Joe’s element contains an element Sam, and Martha’s element contains an element Dave, then both Joe’s and Martha’s children are considered to be Sam and Dave. Each person in the census has zero, one, or two parents.

    This use case is based on an input document named census.xml, with the following DTD:

      <!DOCTYPE census [
        <!ELEMENT census (person*)>
        <!ELEMENT person (person*)>
        <!ATTLIST person
             
    name     ID      #REQUIRED
              spouse   IDREF   #IMPLIED
              job      CDATA   #IMPLIED >
      ]>

    The following census data describes two friendly families that have several intermarriages:

      <census>
        <person name="Bill" job="Teacher">
          <person name="Joe" job="Painter" spouse="Martha">
            <person name="Sam" job="Nurse">
              <person name="Fred" job="Senator" spouse="Jane">
              </person>
            </person>
            <person name="Karen" job="Doctor" spouse="Steve">
            </person>
          </person>
          <person name="Mary" job="Pilot">
            <person name="Susan" job="Pilot" spouse="Dave">
            </person>
          </person>
        </person>
        <person name="Frank" job="Writer">
          <person name="Martha" job="Programmer" spouse="Joe">
            <person name="Dave" job="Athlete" spouse="Susan">
            </person>
          </person>
          <person name="John" job="Artist">
            <person name="Helen" job="Athlete">
            </person>
            <person name="Steve" job="Accountant" spouse="Karen">
              <person name="Jane" job="Doctor" spouse="Fred">
              </person>
            </person>
          </person>
        </person>
      </census>
      Question 1. Find Martha's spouse:
     
    <xsl:strip-space elements="*"/>

      <xsl:template match="person[@spouse='Martha']">
        <xsl:copy>
          <xsl:copy-of select="@*"/>
        </xsl:copy>
      </xsl:template>
      Question 2. Find parents of athletes:
      <xsl:template match="census">
        <xsl:variable name="everyone" select="//person"/>
        <result>
          <!-- For each person with children -->
         <xsl:for-each select="$everyone[person]">
           <xsl:variable name="spouse"
               select="$everyone[@spouse=current()/@name]"/>
           <xsl:if test="./person/@job = 'Athlete' or
                      $spouse/person/@job = 'Athlete'">
             <xsl:copy>
               <xsl:copy-of select="@*"/>
             </xsl:copy>
           </xsl:if>
         </xsl:for-each>
       </result>
      </xsl:template>
     
      Question 3. Find people who have the same job as one of their parents:

    Try it yourself.

      Question 4. List names of parents and children who have the same job, and list
      their jobs:
      <xsl:template match="census">
        <xsl:variable name="everyone" select="//person"/>
        <result>
           <!-- For each person with children -->
          <xsl:for-each select="$everyone[person]">

            <xsl:variable name="spouse" 
                select="$everyone[@spouse=current()/@name]"/>

            <xsl:apply-templates select="person[@job = current()/@job]">
              <xsl:with-param name="parent" select="@name"/>
            </xsl:apply-templates>

            <xsl:apply-templates select="person[@job = $spouse/@job]">
              <xsl:with-param name="parent" select="$spouse/@name"/>
            </xsl:apply-templates>

          </xsl:for-each>
        </result>
      </xsl:template>

      <xsl:template match="person">
        <xsl:param name="parent"/>
        <match parent="{$parent}" child="{@name}" job="{@job}"/>
      </xsl:template>
      Question 5. List name-pairs of grandparents and grandchildren:
      <xsl:template match="census">
        <xsl:variable name="everyone" select="//person"/>
        <result>
          <!-- For each grandchild -->
          <xsl:for-each select="$everyone[../../../person]">
            <!-- Get the grandparent1 (guaranteed to exist by for each -->
            <grandparent name="{../../@name}" grandchild="{@name}"/>
            <!-- Get the grandparent2 is grandparent1's spouse if listed -->
            <xsl:if test="../../@spouse">
              <grandparent name="{../../@spouse}" grandchild="{@name}"/>
            </xsl:if>
           <!-- Get the names of this person's parent's spouse
              (i.e. their mother or father as the case may be) -->
            <xsl:variable name="spouse-of-parent" select="../@spouse"/>
            <!-- Get parents of spouse-of-parent, if present -->
            <xsl:variable name="gp3"
              select="$everyone[person/@name=$spouse-of-parent]"/>
            <xsl:if test="$gp3">
              <grandparent name="{$gp3/@name}" grandchild="{@name}"/>
              <xsl:if test="$gp3/@spouse">
                <grandparent name="{$gp3/@spouse}" grandchild="{@name}"/>
              </xsl:if>
            </xsl:if>
          </xsl:for-each>
        </result>
      </xsl:template>
      Question 6. Find people with no children:
      <xsl:strip-space elements="*"/>
      <xsl:template match="census">
        <xsl:variable name="everyone" select="//person"/>
        <result>
          <xsl:for-each select="$everyone[not(./person)]">
            <xsl:variable name="spouse"
            select="$everyone[@name = current()/@spouse]"/>
            <xsl:if test="not ($spouse) or not($spouse/person)">
              <xsl:copy-of select="."/>
            </xsl:if>
          </xsl:for-each>
        </result>
      </xsl:template>
      Question 7. List the names of all Joe's descendants. Show each descendant as an
      element with the descendant's name as content and his or her marital status and
      number of children as attributes. Sort the descendants in descending order by
      number of children and secondarily in alphabetical order by name:
      <xsl:variable name="everyone" select="//person"/>

      <xsl:template match="census">
        <result>
          <xsl:apply-templates select="//person[@name='Joe']"/>
        </result>
      </xsl:template>

      <xsl:template match="person">

        <xsl:variable name="all-desc">
          <xsl:call-template name="descendants">
            <xsl:with-param name="nodes" select="."/>
          </xsl:call-template>
        </xsl:variable>
        <xsl:for-each select="exsl:node-set($all-desc)/*">
          <xsl:sort select="count(./* | $everyone[@name = current()/@spouse]/*)"
          order="descending" data-type="number"/>
          <xsl:sort select="@name"/> 
          <xsl:variable name="mstatus" 
               select="normalize-space(
                    substring('No Yes',boolean(@spouse)* 3+1,3))"/> 
          <person married="{$mstatus}" 
               nkids="{count(./* | $everyone[@name = current()/@spouse]/*)}">
               <xsl:value-of select="@name"/>
          </person>
        </xsl:for-each>
      </xsl:template>

      <xsl:template name="descendants"> 
        <xsl:param name="nodes"/> 
        <xsl:param name="descendants" select="/.."/>

        <xsl:choose>
          <xsl:when test="not($nodes)"> 
            <xsl:copy-of select="$descendants"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:call-template name="descendants">
              <xsl:with-param name="nodes" select="$nodes[position() > 1] |
                $nodes[1]/person | id($nodes[1]/@spouse)/person"/> 
              <xsl:with-param name="descendants" select="$descendants |
                $nodes[1]/person | id($nodes[1]/@spouse)/person"/> 
             </xsl:call-template> 
          </xsl:otherwise>
        </xsl:choose>
      
      </xsl:template>

    This example accomplishes the query, but it isn’t pretty! The complications come from the need to collect all descendants into a node set so they can be sorted. This forces the use of the node-set extension function. It also means that theid( )function will not help find the spouse because it only works relative to the node’s document. However, the nodes are copies of the original nodes and thus do not have the same document. This situation forces you to go after the spouse elements in a much more cumbersome way by searching for a variable containing all person elements. Contrast this solution to the following XQuery solution:

      define function descrip (element $e) returns element
     
    {
         let $kids := $e/* union $e/@spouse=>person/*
         let $mstatus := if ($e[@spouse]) then "Yes" else "No"
         return
            <person married={ $mstatus } nkids={ count($kids) }>{ $e/@name/text() }
            </person>
      define function descendants (element $e)
      {
        
    if (empty($e/* union $e/@spouse=>person/*))
        
    then $e
        
    else $e union descendants($e/* union $e/@spouse=>person/*)
     
    }

      descrip(descendants(//person[@name = "Joe"])) sortby(@nkids descending, .)

    More XML Tutorials Articles
    More By O'Reilly Media


       · This article is an excerpt from the "XSLT Cookbook, Second Edition," published by...
     
     

    Buy this book now. This article is excerpted from chapter nine of the XSLT Cookbook, Second Edition, written by Sal Mangano (O'Reilly; ISBN: 0596009747). Copyright © 2007 O'Reilly Media, Inc. Check it out today at your favorite bookstore. Buy this book now.

    XML TUTORIALS ARTICLES

    - Creating RSS 2.0 Feeds
    - Using Modules in Your RSS Feed
    - RSS 2.0
    - Querying XML: Use Cases
    - Joins and Query Use with XML
    - Solving Problems by Querying XML
    - Performing Set Operations When Querying XML
    - Querying XML
    - Handling Data for Ajax with JSON
    - Handling XML Data for Ajax
    - XML and JSON for Ajax





    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 3 hosted by Hostway