RE: [xsl] The notion of Inheritance?

Subject: RE: [xsl] The notion of Inheritance?
From: William Bagby <williamb@xxxxxxxxx>
Date: Thu, 29 Mar 2001 12:28:32 -0500
> OK, so you're matching person[id = 2 or id = 3] with a template:
> 
> <xsl:template match="person[id = 2 or id = 3]">
>    ...
> </xsl:template>

Almost. It's not exactly what I want.  I should've been a little more clear.
I would only want to match one id at a time.  For example, suppose I have a
URL:

http://www.mydomain.com/people/people.xml?id=2

where people.xml is my aforementioned XML 'database'.  The result I would
like is:

<person>
	<id>2</id>
	<first-name>Mary</first-name>
	<last-name>Jacobs</last-name>
	<physical>
		<eyes>brown</eyes>
		<hair>black</hair>
		<height>6'1"</height>
	</physical>
	<occupation>Welder</occupation>
</person>

So the XSL would perform the following steps:

1. Make a copy of person[id = 1].
2. Traverse the nodes, at each node checking whether person[id = 2] is
defined.
3. If it is, overwrite the copied node.  If not, leave it alone.

I would like the output itself to be XML. I am also making the assumtion
that person[id != 1] cannot have any nodes that person[id = 1] does not
have.  This may make things a bit easier.

Thanks for all your help.  I really appreciate it.

William.

-----Original Message-----
From: Jeni Tennison [mailto:mail@xxxxxxxxxxxxxxxx]
Sent: Thursday, March 29, 2001 4:34 AM
To: William Bagby
Cc: XSL Mailing List (E-mail)
Subject: Re: [xsl] The notion of Inheritance?


Hi William,

> Suppose I want to match id=2 and id=3 (respectively) and transform
> them to separate XMLs, using id=1 as the default:

OK, so you're matching person[id = 2 or id = 3] with a template:

<xsl:template match="person[id = 2 or id = 3]">
   ...
</xsl:template>

>From within this template, you can always get at person id=1 with one
of the paths:

  ../person[id = 1]  (id child equals '1')
  ../person[1]       (first person in the list)

To do the defaulting, it's probably easiest to go through the elements
within the default person and copy them unless there's an equivalent
element in the person that you're considering. Since the elements are
nested, you should probably use a recursive solution where you pass
the overriding information down as you work through the person.

So, from within your template, apply templates to the person with id =
1, passing the person that you're looking at as a parameter.  I'll use
an 'inherit' mode to avoid clashes between the templates:

<xsl:template match="person[id = 2 or id = 3]">
   <xsl:apply-templates select="../person[id = 1]" mode="inherit">
      <xsl:with-param name="override" select="." />
   </xsl:apply-templates>
</xsl:template>

Then, you want to have a template that matches elements with element
content (like person and physical). They copy themselves and then
apply templates to their child elements, passing the relevant child of
the $override node down to the next level:

<xsl:template match="*[*]" mode="inherit">
   <xsl:param name="override" />
   <xsl:copy>
      <xsl:for-each select="*">
         <xsl:apply-templates select="." mode="inherit">
            <xsl:with-param name="override"
               select="$override/*[name() = name(current())]" />
         </xsl:apply-templates>
      </xsl:for-each>
   </xsl:copy>
</xsl:template>

When you get to textual elements, you want to see if the $override
element exists - if it does, it should be copied, otherwise the
current node should be copied:

<xsl:template match="*[not(*)]" mode="inherit">
   <xsl:param name="override" />
   <xsl:copy-of select="$override | current()[not($override)]" />
</xsl:template>

I hope that helps,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread