Family Tree

This chapter is based on Chapter 23 of Elliotte Rusty Harold's book [Harold 1999], plus additional material from the web.

Introduction

Before introducing the course project, it will be instructive to work through a similar exercise in order to achieve a better understanding of what is required. Here are the basic steps.

The family tree DTD consists of three components. Figure 1 is the DTD describing an individual person.

<?xml version="1.0" encoding="UTF-8"?>

<!ENTITY % event "(place?, date?)">
<!ENTITY % reference "person IDREF #REQUIRED">

<!ELEMENT place (#PCDATA)>

<!ELEMENT date (#PCDATA)>

<!ELEMENT person (name | birth | death | father | mother |
                  spouse | note)*>
<!ATTLIST person id  ID      #REQUIRED
                 sex (m | f) #IMPLIED>

<!ELEMENT name (given?, surname?)>

<!ELEMENT given (#PCDATA)>

<!ELEMENT surname (#PCDATA)>

<!ELEMENT birth %event;>

<!ELEMENT death %event;>

<!ELEMENT father EMPTY>
<!ATTLIST father %reference;>

<!ELEMENT mother EMPTY>
<!ATTLIST mother %reference;>

<!ELEMENT spouse EMPTY>
<!ATTLIST spouse %reference;>

<!ELEMENT note (#PCDATA)>


Figure 1 : The Person DTD Document

Most importantly, each person is identified by a unique ID; this will be invaluable for later processing of individuals. This DTD also follows the conventional western view that a person has one father and one mother, one birthday, one death date, and a single name. Dates are left vague because historical data may be vague; additionally the sex may not be known of babies that died young. Figure 2 brings people together as families.

<?xml version="1.0" encoding="UTF-8"?>

<!ENTITY % person SYSTEM "person.dtd">
%person;

<!ELEMENT family (husband?, wife?, child*, marriage*,
                  divorce*, note*)>

<!ELEMENT husband EMPTY>
<!ATTLIST husband %reference;>

<!ELEMENT wife EMPTY>
<!ATTLIST wife %reference;>

<!ELEMENT child EMPTY>
<!ATTLIST child %reference;>

<!ELEMENT marriage %event;>

<!ELEMENT divorce %event;>


Figure 2 : The Family DTD Document

Note that this DTD includes the person DTD as a SYSTEM entity. A family is generally composed of a husband, a wife, and zero or more children. Either the husband or the wife is optional. Separating people from families makes maintenance easier! Finally, Figure 3 brings together people and families as components of a family tree.

<?xml version="1.0" encoding="UTF-8"?>

<!ENTITY % family SYSTEM "family.dtd">
%family;

<!ELEMENT family-tree (person | family)*>


Figure 3 : The Family Tree DTD Document

Note that this DTD includes the family DTD as a SYSTEM entity. Figure 4 shows the (incomplete) Farmer family tree as a valid XML document.

<?xml version="1.0"?>
<!DOCTYPE family-tree SYSTEM "family-tree.dtd">

<family-tree>

  <person id="p5" sex="m">
    <name>
      <given>Alfred Ernest</given>
      <surname>Farmer</surname>
    </name>
  </person>

  <person id="p6" sex="m">
    <name>
      <given>Ronald Alfred</given>
      <surname>Farmer</surname>
    </name>
    <birth>
      <place>London</place>
      <date>27 April, 1922</date>
    </birth>
    <father person="p5"/>
  </person>

  <person id="p7" sex="f">
    <name>
      <given>Daisy</given>
      <surname>Farmer</surname>
    </name>
  </person>

  <person id="p8" sex="m">
    <name>
      <given>Stanley</given>
      <surname>Small</surname>
    </name>
    <birth>
      <place>Catford, London</place>
      <date>11 April, 1924</date>
    </birth>
  </person>

  <person id="p9" sex="f">
    <name>
      <given>Nansi</given>
      <surname>Small</surname>
    </name>
    <birth>
      <place>London</place>
      <date>17 January, 1929</date>
    </birth>
  </person>

  <person id="p10" sex="m">
    <name>
      <given>Michael Ronald</given>
      <surname>Farmer</surname>
    </name>
    <birth>
      <place>Queen Charlotte's Hospital, London</place>
      <date>10 November, 1945</date>
    </birth>
    <father person="p6"/>
    <mother person="p7"/>
    <spouse person="p11"/>
  </person>

  <person id="p11" sex="f">
    <name>
      <given>Susan Anne</given>
      <surname>Small</surname>
    </name>
    <birth>
      <place>Brisbane, Australia</place>
    </birth>
    <father person="p8"/>
    <mother person="p9"/>
    <spouse person="p10"/>
  </person>

  <person id="p12" sex="m">
    <name>
      <given>Robert</given>
      <surname>Small</surname>
    </name>
    <father person="p8"/>
    <mother person="p9"/>
  </person>

  <family>
    <husband person="p6"/>
    <wife person="p7"/>
    <child person="p10"/>
  </family>

  <family>
    <husband person="p8"/>
    <wife person="p9"/>
    <child person="p11"/>
    <child person="p12"/>
  </family>

  <family>
    <husband person="p10"/>
    <wife person="p11"/>
    <marriage>
      <place>Lewisham, London</place>
      <date>12 April, 1990</date>
    </marriage>
  </family>

</family-tree>


Figure 4 : The Farmer Family Tree in XML

If this XML document is transformed by the default rule for the root node, then the result is anodyne, as shown in Figure 5. Only the text nodes are output by default.


      Alfred Ernest
      Farmer
      Ronald Alfred
      Farmer
      London
      27 April, 1922
      Daisy
      Farmer
      Stanley
      Small
      Catford, London
      11 April, 1924
      Nansi
      Small
      London
      17 January, 1929
      Michael Ronald
      Farmer
      Queen Charlotte's Hospital, London
      10 November, 1945
      Susan Anne
      Small
      Brisbane, Australia
      Robert
      Small
      Lewisham, London
      12 April, 1990


Figure 5 : Default Processing the Farmer Family Tree

Note that this output file has been pruned of most of its whitespace. Even so, it doesn't make sense unless you know the original format. The default XSLT needs to be augmented to include extra information (what are we describing) and hyperlinks (to relatives) in whatever markup language we're using (HTML in this case). The following link shows one possible version of the Farmer family tree as a stand-alone HTML document. Figure 6 is Mick's final XSLT document that processes the XML document starting with the document root to generate the document linked above.

<?xml version="1.0"?>
<!-- family2html -->

<xsl:stylesheet version="1.0"
		xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <xsl:template match="/">
    <HTML>
      <HEAD>
        <TITLE>Family Tree</TITLE>
      </HEAD>
      <BODY>
        <xsl:apply-templates select="family-tree"/>
      </BODY>
    </HTML>
  </xsl:template>
  
  <xsl:template match="family-tree">
    <H1>Family Tree</H1>
    <H2>Families</H2>
    <xsl:apply-templates select="family"/>
    <H2>People</H2>
    <xsl:apply-templates select="person"/>
  </xsl:template>

  <xsl:template match="family">
    <UL>
      <xsl:apply-templates select="husband"/>
      <xsl:apply-templates select="wife"/>
      <xsl:apply-templates select="child"/>
    </UL>
  </xsl:template>

  <xsl:template match="husband">
    <LI>Husband:
      <A href="#{@person}">
        <xsl:value-of select="id(@person)/name"/>
      </A>
    </LI>
  </xsl:template>

  <xsl:template match="wife">
    <LI>Wife:
      <A href="#{@person}">
        <xsl:value-of select="id(@person)/name"/>
      </A>
    </LI>
  </xsl:template>

  <xsl:template match="child">
    <LI>Child:
      <A href="#{@person}">
        <xsl:value-of select="id(@person)/name"/>
      </A>
    </LI>
  </xsl:template>

  <xsl:template match="person">
    <H3>
      <A name="{@id}"/>
      <xsl:value-of select="name"/>
    </H3>
    <UL>
      <xsl:if test="birth">
        <LI>Born: <xsl:value-of select="birth"/></LI>
      </xsl:if>
      <xsl:if test="death">
        <LI>Died: <xsl:value-of select="death"/></LI>
      </xsl:if>
      <xsl:apply-templates select="father"/>
      <xsl:apply-templates select="mother"/>
    </UL>
    <P>
      <xsl:apply-templates select="note"/>
    </P>
  </xsl:template>

  <xsl:template match="father">
    <LI>
      <A href="#{@person}">Father</A>
    </LI>
  </xsl:template>

  <xsl:template match="mother">
    <LI>
      <A href="#{@person}">Mother</A>
    </LI>
  </xsl:template>

</xsl:stylesheet>


Figure 6 : Family Tree Stylesheet

The most important aspect of this structure is that individual persons have unique IDs; this enables the style sheet to locate individual person's details. It also means that the family tree must be complete, i.e. every person referenced must be included as an individual person.

Note that not all of the information is made available with this transformation. Feel free to augment these transformations by providing every piece of information provided in the XML document. Also, consider how to generate a more formal and traditional family tree. It's not easy, especially in raw HTML!

References

  1. [an error occurred while processing this directive]