« Options | Main | Linked fields »

Modular XSLT, part 2: Simple export

As you know you can export or request data from FileMaker in XML and then transform the XML using a XSLT stylesheet into some other format. The question is: how do you approach writing such a stylesheet? Are there some universal techniques? Can you save some effort?

Here's a general tutorial, covering a basic export to simple XML format. As you'll see it isn't just a look-ma-it's-XML sample, but more like a foundation for any many well, at least some XSL-transformation problems.

The tutorial assumes you know XSLT basics and maybe have even tried to export something from FileMaker using the built-in XSLT processor. For example, you must understand what <xsl:temlplate> or <xsl:param> are for. If you don't know XLST, you might want to start from some XSLT Tutorial, like this quick one by W3Schools or that more detailed one by Zvon; this is where I started.

Technorati Tags:

You might also want to grab the sample files I've used to write the tutorial.

Starting point

Assume we have a FileMaker database of news and want to export them to Atom, an XML-based feed format with the same purpose as RSS. Here's the FileMaker file we have:

2006.05.15.01.png

and here's a sample of the Atom XML, taken directly from the specification:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Example Feed</title>
 <subtitle>Insert witty or insightful remark here</subtitle>
 <link href="http://example.org/"/>
 <updated>2003-12-13T18:30:02Z</updated>
 <author>
   <name>John Doe</name>
   <email>johndoe@example.com</email>
 </author>
 <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>

 <entry>
   <title>Atom-Powered Robots Run Amok</title>
   <link href="http://example.org/2003/12/13/atom03"/>
   <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
   <updated>2003-12-13T18:30:02Z</updated>
   <summary>Some text.</summary>
 </entry>

</feed>

This is a simplified sample, the actual format is more complex, but it's exactly what we need for the tutorial. Let's assume this is a full specification of a non-existing Simple Atom standard. Let's also assume we have these timestamps (the strings like 2003-12-13T18:30:02Z) right in the database and don't need to format them; I'll comment more on this below. Our starting point is a FileMaker file and a sample/specification of the result:

2006.05.15.02.png

What do we do next?

First we need to think, of course. We need to understand what will be translated into what. I must admit the sample is artificial and was thought up to match the output, so the task isn't difficult. But let's start from the beginning.

First we need to look at the structure of the target file. Every XML file has exactly one root element; here this element is feed. Feed has a handful of elements, some of which, namely entries are especially important, because there could be many of them. So the framework of the target file is the following:

<feed>
  <entry /> <!-- many of them -->
</feed>

Now let's compare this structure with the structure of FileMaker raw export format, FMPXMLRESULT. It's more complex, like this:

<FMPXMLRESULT>
  <METADATA>
    <FIELD /> <!-- many of them -->
  </METADATA>
  <RESULTSET>
    <ROW /> <!-- many of them -->    
  </RESULTSET>
</FMPXMLRESULT>

We can see that these two structures are quite similar. If we ignore the METADATA part of FMPXMLRESULT then both documents can be viewed as having one root element and many identical elements within it (FileMaker's grammar is a bit different, because the identical elements belong to the RESULTSET element, not the root FMPXMLRESULT element, but since there could be only one RESULTSET, this difference is inessential).

This means we can make a nearly direct transformation. We'll export records from the Piece of News table, include the related data from News Channel and Author, which will be identical for all records in the exported file and use the latter only once to make the feed's header. Here's our export order as it looks from the Piece of News table:

2006.05.15.03.png

Of course, not all export tasks are that simple, but this post is about simple exports :)

A not-so-simple export could be an export having two sets of multiple identical entries or a set that has an undefined number of entries with an undefined number of sub-entries, like maybe a list of invoices with all line items. These documents cannot be build up as easily as our Simple Atom sample.

Now let's go to the next step, which is:

Step 1. Make a standalone XSLT file to build the resulting document

The sole purpose of this XLST file is to create the resulting document. The file will be totally independent from FileMaker grammar or data and won't be selected in the "Export" dialog; it's an auxiliary file. You can think of it as of a function or set of functions you pass certain parameters to or may be as Simple Atom Application Program Interface (API); this is very close to what it's going to be. As soon as you're ready with the file, the next step will be to write an adapter between your file and the API.

In spite of high-tech sound of the “API” acronym, writing such a file is a very straightforward proccess; actually it's nearly mechanical. As you know the structure of the document is basically a feed containing multiple entries.

<feed>
 <entry /> <!-- many of them -->
</feed>

Now let's go a bit deeper. Feed also contains other elements, but only once. Most of these elements are simple, but author has its own structure:

<feed>
  <title />
  <subtitle />
  <link />
  <updated />
  <author> <!-- this element has its own structure -->
    <name />
    <email />
  </author>
  <id />
  ...
</feed>

And finally feed contains an undefined number of entry elements, which also have their own structure:

<feed>
  ...
  <entry> <!-- undefined number; has its own structure -->
    <title />
    <link />
    <id />
    <updated />
    <summary />
  </entry>
</feed>

We write the API in few simple step:

  • Start with an empty stylesheet, define the output method and encoding.
  • Make a named template for every element that has any structure or can occur several times.
  • Make a parameter for every element or attribute.
  • Lay out the document structure in the templates and insert the just created parameters as placeholders. Use <xsl:value-of> for simple parameters and <xsl:copy-of> for complex ones.
Start with an empty stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >

</xsl:stylesheet> 
Define the output method and encoding

Check what output method and encoding you need and simply write this in XSLT language. In our case we output XML using Unicode:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:output method="xml" indent="yes" encoding="utf-8" /> 

</xsl:stylesheet> 
Make named templates for complex elements

Complex elements are elements that have their own structure or occur many times. Having their own structure means having more than one associated value, like child elements or multiple attributes or maybe an attribute and contents. Simple elements are that:

<simple>I'm simple</simple>
<simple value="I'm simple too" />

and complex are that:

<complex>
  <who>I'm</who>
  <what>complex</what>
</complex>

<complex who="I'm">complex</complex>
<complex who="I'm" what="complex" />

<complex>We're complex</complex>
<complex>Because there's a lot of us</complex>

In Simple Atom we have 3 complex elements: feed and author have structure and entry both has structure and can occur many times. Let's make a template for each:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:output method="xml" indent="yes" encoding="utf-8" /> 

  <xsl:template name="feed">
  </xsl:template>
  
  <xsl:template name="author">
  </xsl:template>
  
  <xsl:template name="entry">
  </xsl:template>

</xsl:stylesheet> 
Make parameters for contents of these elements

Now we need to augment each of these templates with parameters for every element or attribute they contain, including complex ones, of course. For example, the feed template would look like that:

  ...
  <xsl:template name="feed">
    <xsl:param name="title" />
    <xsl:param name="subtitle" />
    <xsl:param name="link" />
    <xsl:param name="updated" />
    <xsl:param name="author" />  <!-- complex -->
    <xsl:param name="id" />
    <xsl:param name="entries" /> <!-- complex -->
  </xsl:template>
  ...

The parameter for entries is written in plural to indicate the fact there could be many of them. Other templates are similar:

  ...
  <xsl:template name="author">
    <xsl:param name="name" />
    <xsl:param name="email" />
  </xsl:template>
  
  <xsl:template name="entry">
    <xsl:param name="title" />
    <xsl:param name="link" />
    <xsl:param name="id" />
    <xsl:param name="updated" />
    <xsl:param name="summary" />
  </xsl:template>
  ...
Lay out the structure and data placeholders. Use <xsl:value-of> for simple parameters and <xsl:copy-of> for complex ones.

So far we haven't created any part of the final document yet: all we have is XSLT code that doesn't produce anything. Now is the time to add actual document content. Place the structural elements in every template and replace the data elements with references to the just created parameters, using <xsl:value-of> for simple elements and <xsl:copy-of> for complex ones (to keep their structure). The feed template will be the following:

  ...
  <xsl:template name="feed">
    <xsl:param name="title" />
    <xsl:param name="subtitle" />
    <xsl:param name="link" />
    <xsl:param name="updated" />
    <xsl:param name="author" /> 
    <xsl:param name="id" />
    <xsl:param name="entries" />
    <feed xmlns="http://www.w3.org/2005/Atom">
      <title><xsl:value-of select="$title" /></title>
      <subtitle><xsl:value-of select="$subtitle" /></subtitle>
      <link href="{$link}"/>
      <updated ><xsl:value-of select="$updated" /></updated>
      <xsl:copy-of select="$author" />
      <id><xsl:value-of select="$id" /></id>
      <xsl:copy-of select="$entries" />
    </feed>
  </xsl:template>
  ...

As you can see you simply write down the structure and replace all data with <xsl:value-of>'s and <xsl:copy-of>'s. If you have a sample file you can do it in minutes. Here's the whole API:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:output method="xml" indent="yes" encoding="utf-8" /> 

  <xsl:template name="feed">
    <xsl:param name="title" />
    <xsl:param name="subtitle" />
    <xsl:param name="link" />
    <xsl:param name="updated" />
    <xsl:param name="author" />
    <xsl:param name="id" />
    <xsl:param name="entries" />
    <feed xmlns="http://www.w3.org/2005/Atom">
      <title><xsl:value-of select="$title" /></title>
      <subtitle><xsl:value-of select="$subtitle" /></subtitle>
      <link href="{$link}"/>
      <updated ><xsl:value-of select="$updated" /></updated>
      <xsl:copy-of select="$author" />
      <id><xsl:value-of select="$id" /></id>
      <xsl:copy-of select="$entries" />
    </feed>
  </xsl:template>
  
  <xsl:template name="author">
    <xsl:param name="name" />
    <xsl:param name="email" />
    <author>
      <name><xsl:value-of select="$name" /></name>
      <email><xsl:value-of select="$email" /></email>
    </author>
  </xsl:template>
  
  <xsl:template name="entry">
    <xsl:param name="title" />
    <xsl:param name="link" />
    <xsl:param name="id" />
    <xsl:param name="updated" />
    <xsl:param name="summary" />
    <entry>
      <title  ><xsl:value-of select="$title" /></title>
      <link href="{$link}"/>
      <id><xsl:value-of select="$id" /></id>
      <updated><xsl:value-of select="$updated" /></updated>
      <summary><xsl:value-of select="$summary" /></summary>
    </entry>
  </xsl:template>

</xsl:stylesheet> 

Let's take a step back and look at what we have made:

2006.05.15.04.png

the “API” or an XSLT object that can build a Simple Atom document. I call it “an object” because it hides all the implementation details behind a simple interface, “incapsulates” them. For example, as soon as you have the object, you don't even need to know the target document is XML or what encoding it is supposed to have. You don't need to bother whether some values go into element contents or attributes. All you need is to call the interface functions and supply correct parameters. Let's go to the next step to see how we do this.

Step 2: make an XSLT adapter between your FileMaker file and the API

To use this file we'll make another stylesheet that will actually process the exported FMPXMLRESULT grammar and use the just created API to build the target file. Here are the steps:

  • Start with an empty stylesheet, define used grammars and add the <exclude-result-prefixes> attrbute.
  • Add a reference to the just written API.
  • Call the main API template and pass all parameters using other templates as necessary.
Start with an empty stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  
</xsl:stylesheet> 
Define used grammars and add the <exclude-result-prefixes> attrbute
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
  exclude-result-prefixes="xsl fmp">

</xsl:stylesheet> 
Add a reference to the just written API
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
  exclude-result-prefixes="xsl fmp">

  <xsl:include href="Simple Atom.xslt" />

</xsl:stylesheet> 
Call the main API template and pass all the necessary parameters using other templates as necessary.

XSLT is a functional language and it “emphasizes the evaluation of expressions, rather than execution of commands” (taken from comp.lang.functional FAQ). We accomplish the whole task of transforming the source document into the target in a single call to the main <xsl:template>, which is feed:

  <xsl:template match="/">
    <xsl:call-template name="feed">
    ...
    </xsl:call-template>
  </xsl:template>

All we need to do is to supply the parameters:

  <xsl:template match="/">
    <xsl:call-template name="feed">
      <xsl:with-param name="title"    select="" />
      <xsl:with-param name="subtitle" select="" />
      <xsl:with-param name="link"     select="" />
      <xsl:with-param name="updated"  select="" />
      <xsl:with-param name="author" />
      <xsl:with-param name="id"       select="" />
      <xsl:with-param name="entries" />
    </xsl:call-template>
  </xsl:template>

To pass the complex parameter author we use the author template:

      ...
      <xsl:with-param name="author">
        <xsl:call-template name="author">
          <xsl:with-param name="name"  select="" />
          <xsl:with-param name="email" select="" />
        </xsl:call-template>
      </xsl:with-param>
      ...

And to pass entries we loop through the found set and call the entry template for every record:

      ...
      <xsl:with-param name="entries">
        <xsl:for-each select="//fmp:ROW">
          <xsl:call-template name="entry">
            <xsl:with-param name="title"   select="" />
            <xsl:with-param name="link"    select="" />
            <xsl:with-param name="id"      select="" />
            <xsl:with-param name="updated" select="" />
            <xsl:with-param name="summary" select="" />
          </xsl:call-template>
        </xsl:for-each>
      </xsl:with-param>
      ...

We're almost ready. Now we can already test the file without real data using text placeholders. Here's the whole My News to Simple Atom.xslt file with the placeholders:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
  exclude-result-prefixes="xsl fmp">

  <xsl:include href="Simple Atom.xslt" />

  <xsl:template match="/">
    <xsl:call-template name="feed">
      <xsl:with-param name="title"    select="'title'" />
      <xsl:with-param name="subtitle" select="'subtitle'" />
      <xsl:with-param name="link"     select="'link'" />
      <xsl:with-param name="updated"  select="'updated'" />
      <xsl:with-param name="author">
        <xsl:call-template name="author">
          <xsl:with-param name="name"  select="'author name'" />
          <xsl:with-param name="email" select="'author email'" />
        </xsl:call-template>
      </xsl:with-param>
      <xsl:with-param name="id"       select="'id'" />
      <xsl:with-param name="entries">
        <xsl:for-each select="//fmp:ROW">
          <xsl:call-template name="entry">
            <xsl:with-param name="title"   select="'entry title'" />
            <xsl:with-param name="link"    select="'entry link'" />
            <xsl:with-param name="id"      select="'entry id'" />
            <xsl:with-param name="updated" select="'entry updated'" />
            <xsl:with-param name="summary" select="'entry summary'" />
          </xsl:call-template>
        </xsl:for-each>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:template>
</xsl:stylesheet> 

If we export the data from the sample file using the adapter we've just made

2006.05.15.05.png

it will give us a proper Atom document with correct number of entries, but with fake data, like this:

<?xml version="1.0" encoding="utf-8"?>
<feed>
<title>title</title>
<subtitle>subtitle</subtitle>
<link href="link"/>
<updated>updated</updated>
<author>
<name>author name</name>
<email>author email</email>
</author>
<id>id</id>
<entry>
<title>entry title</title>
<link href="entry link"/>
<id>entry id</id>
<updated>entry updated</updated>
<summary>entry summary</summary>
</entry>
</feed>

Now the only thing you need is to substitute the text placeholders with references to actual FileMaker fields. If your export order is that (the picture is same as above):

2006.05.15.03.png

then the final fully working adapter would be that:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fmp="http://www.filemaker.com/fmpxmlresult"
  exclude-result-prefixes="xsl fmp">

  <xsl:include href="Simple Atom.xslt" />

  <xsl:template match="/">
    <xsl:call-template name="feed">
      <xsl:with-param name="id"       select=".//fmp:ROW[1]/fmp:COL[1]/fmp:DATA" />
      <xsl:with-param name="title"    select=".//fmp:ROW[1]/fmp:COL[2]/fmp:DATA" />
      <xsl:with-param name="subtitle" select=".//fmp:ROW[1]/fmp:COL[3]/fmp:DATA" />
      <xsl:with-param name="link"     select=".//fmp:ROW[1]/fmp:COL[4]/fmp:DATA" />
      <xsl:with-param name="updated"  select=".//fmp:ROW[1]/fmp:COL[5]/fmp:DATA" />
      <xsl:with-param name="author">
        <xsl:call-template name="author">
          <xsl:with-param name="name"  select=".//fmp:ROW[1]/fmp:COL[6]/fmp:DATA" />
          <xsl:with-param name="email" select=".//fmp:ROW[1]/fmp:COL[7]/fmp:DATA" />
        </xsl:call-template>
      </xsl:with-param>
      <xsl:with-param name="entries">
        <xsl:for-each select="//fmp:ROW">
          <xsl:call-template name="entry">
            <xsl:with-param name="id"      select="fmp:COL[8]/fmp:DATA" />
            <xsl:with-param name="title"   select="fmp:COL[9]/fmp:DATA" />
            <xsl:with-param name="link"    select="fmp:COL[10]/fmp:DATA" />
            <xsl:with-param name="updated" select="fmp:COL[11]/fmp:DATA" />
            <xsl:with-param name="summary" select="fmp:COL[12]/fmp:DATA" />
          </xsl:call-template>
        </xsl:for-each>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:template>
</xsl:stylesheet> 

Note that we explicitly reference the first row (fmp:ROW[1]) to get the feed and author attributes.

A bird's-eye view

Simplifications made

The described sample is a good start, but of course, it's simplified. I already wrote about this above but it's important: the sample was that simple because the structure of the target document didn't differ much from the the structure of FMPXMLRESULT. There's plenty of document formats that are much more different and they won't be so easy to export, of course. I'm going to write more on this later.

Further modularization

In the sample we assumed we have all the data we need right in our FileMaker file. Of course, this may be not the case. Look for example at the date format:

<updated>2003-12-13T18:30:02Z</updated>

This format is described in RFC3339. In your FileMaker file you probably have the date stored differently, may be in separate date, time and time zone fields. How would you export it in the required format?

Of course, you can read the specification and write a calculation to assemble such a timestamp right in FileMaker, but if you do this, you'll add a piece of data that is completely alien to your application. A better way would be to leave the fields you already have and write another API file to make such a date:

2006.05.15.06.png

Such an API could take date, time and time zone parameters and make a date in RFC3339 format. You could include the additional API in your adapter and first make a proper date and then pass it to the Simple Atom API.

  ...
  <xsl:include href="Simple Atom.xslt" />
  <xsl:include href="RFC3339.xslt" />
  ...
    ...
      ...
        <xsl:with-param name="updated" />
          <xsl:call-template name="RFC3339">
            <xsl:with-param name="date" select ='...' />
            <xsl:with-param name="time" select ='...' />
            <xsl:with-param name="zone" select ='...' />
          </xsl:call-template>
        </xsl:with-param>
        ...
Your own “formats”

Some APIs you might write could be too low-level to be used “as is”. For example, it could be relatively simple to write an HTML API, but such an API would give you only very generic constructs, like, for example, table or paragraph, while you would like to think in terms of a company style and want things like product description or sidebar.

In this case you might write a second-level API for your own HTML pages. Such an API could have your own functions that include your custom parameters, which will then be transformed to the low-level calls to HTML API. For example, a product template might take simple parameters like name, description, and price and build all the low-level HTML itself, hiding all the unnecessary details.

As with any object-oriented approach this method would allow you to easily change the underground implementation, like actual formatting and arrangement of name, description, and price and don't break anything in the rest of the application.

The number of such APIs can be quite big; some APIs will create just generic elements in the company style; other will call these generic elements to create more specific elements; top-level APIs will build pages out of these blocks.

Of course, writing these APIs won't be so easy as writing tech-style APIs, because the latter are just mechanically transformed directly from the specification, while high-level APIs don't have such a specification; this is where the actual programming begins.

APIs as commodities

It seems that a carefully written generic XSLT API for a complex widely adopted format, such as RTF, HTML or HL7 could have some value on its own. I cannot say there's a market for them out there or that such a task is better suited for the developer community. Of course I could be wrong on this because I don't know about any widely available such APIs, so maybe there's some flaws in the approach I don't see yet... but who knows.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/t/trackback/510343/4906819

Listed below are links to weblogs that reference Modular XSLT, part 2: Simple export:

Comments

Mikhail,

Thank you for posting this information. It has saved me from having to read cover to cover some of the XSLT books on the shelves.

I just have one question and I'll preface my question with some info. Going from FMP to cXML.
cXML output should look like the following for the Header section (has many sections with similar element:attribute pairs):

[Header]
[From]
[Credential domain="NetworkID"]
[Identity]007[/Identity]
[/Credential]
[/From]
[To]
[Credential domain="NetworkId"]
[Identity]1463[/Identity]
[/Credential]
[/To]
[Sender]
[Credential domain="NetworkID"]
[Identity]9647[/Identity]
[SharedSecret]banana[/SharedSecret]
[/Credential]
[UserAgent] Supplier [/UserAgent]
[/Sender]
[/Header]

My question is wether I should treat the [Header] element as the template; use [From] [To] [Sender] as templates; or nest them all into one big one? Does templating support nested templates so that the Sender Credential Identity is accessed seperately from the To Credential Identity?

Thank you for your time,
Davis

Sorry for the bad markup.

f the header has only one "from", "to", and "sender", then technically there's no difference. Only your personal style does matter I typically make such elements separate templates because to me it seems clearer, less ambiguous when I read the code later. I.e.:

[xsl:template name="header"]
[xsl:param name="from" /]
[xsl:param name="to" /]
[xsl:param name="sender" /]
[/xsl:template]

[xsl:template name="from"]
[xsl:param name="credential" /]
[/xsl:template]

[xsl:template name="to"]
[xsl:param name="credential" /]
[/xsl:template]

[xsl:template name="sender"]
[xsl:param name="credential" /]
[xsl:param name="user-agent" /]
[/xsl:template]

[xsl:template name="credential"]
[xsl:param name="identity" /]
[xsl:param name="shared-secret" /]
[/xsl:template]

is probably longer, but very simple: there's no confusion about what's what.

Just incase you don't see this on FMForums:

Ahh the cloud cover has lifted.

Thank you for your time and assistance.

One remaining question:
You mention "If the header has only one", I guess logically there could be many. How would one handle that?

For instance:

[Invoice Partner]
[Contact role="soldTo"]
[Name>Jimmy[/Name]
[/Contact]
[/Invoice Partner]

[Invoice Partner]
[Contact role="remitTo"]
[Name>Jimmy[/Name]
[/Contact]
[/Invoice Partner]

[Invoice Partner]
[Contact role="shipTo"]
[Name>Jimmy[/Name]
[/Contact]
[/Invoice Partner]

I would assume that I would just make individual templates for the different roles:
[xsl:template name="Contact" role="shipTo"]
[xsl:param name="Name" /]
[/xsl:template]

Thanks again,
d

Since the structures are nearly identical, it's certainly better to make a single template that handles them all and then pass the role as a parameter. I.e.

[xsl:template name="contact"]
[xsl:param name="role" /]
[xsl:param name="name" /]

[Contact role="{$role}"]
[Name][xsl:value-of select="$name"][/Name]
[/Contact]
[/xsl:template]

hi,
good site :) Whish you good luck!

Post a comment

If you have a TypeKey or TypePad account, please Sign In