xsl-list
[Top] [All Lists]

Re: XML to XML

2003-03-26 15:47:40
Jim,

Your problem is actually subtler than you may think it is. This isn't just a matter of having multiple templates; it's that you are faced with an "upconversion", which is to say you want to take advantage of information that is only implicit in your source (in the values of nodes, specifically your <Code> elements), and making it explicit in the node structure of your output. In your case, the implicit information in the source is which category goes inside which. You are going from a flat structure to a nested, hierarchical one. Like many upconversions, it's essentially a grouping problem.

Where possible, this kind of "levitation" (getting structure where there was none) is best solved (in my experience) with keys, which are designed to let you retrieve nodes based on associated values. Here, there are two bits of information that are critical. One, to which level should a category be assigned: this is indicated by the string length of its Code child. Two, which category of the next level up does it belong with: this is indicated by the value of the first n-1 characters of the Code, where n is the Code's length. These two bits of logic can be encoded in keys like this:

<xsl:key name="level1" match="Category[string-length(Code)=1]"
  use="'all'"/>

(This one is a convenience. It gets all the Categories A, B, C etc., as long as their Code has one character. It returns them all with the key value of 'all'.)

<xsl:key name="level2" match="Category[string-length(Code)=2]"
  use="substring(Code, 1, 1)"/>

This one matches Categories AA, AB, DZ, FF etc, keying them to the values A (for AA and AB), D, F etc.

<xsl:key name="level3" match="Category[string-length(Code)=3]"
  use="substring(Code, 1, 2)"/>

Same, but matches AAA, AAC, DZC, FFF etc., keying them to AA, DZ, FF etc.

Then,

<xsl:template match="/">
  <Categories>
    <xsl:apply-templates select="key('level1','all')"/>
  </Categories>
</xsl:template>

<xsl:template match="Category[string-length(Code)=1]">
  <!-- matches only level 1 nodes -->
  <LevelOneCategory Code="{Code}" Description="{Description}">
    <xsl:apply-templates select="key('level2',Code)"/>
    <!-- goes and gets the level 2 categories keyed to the value
         of this one's Code -->
  </LevelOneCategory>
</xsl:template>

<xsl:template match="Category[string-length(Code)=2]">
  <!-- matches level 2 nodes -->
  <LevelTwoCategory Code="{Code}" Description="{Description}">
    <xsl:apply-templates select="key('level3',Code)"/>
    <!-- goes and gets the level 3 categories keyed to the value
         of this one's Code -->
  </LevelTwoCategory>
</xsl:template>

<xsl:template match="Category[string-length(Code)=3]">
  <!-- matches level 3 nodes -->
  <LevelThreeCategory Code="{Code}" Description="{Description}"/>
</xsl:template>

Note that this method will be fast and efficient, but it requires you to know in advance how deep your categories go (how many levels to allow for). If this cannot be known until runtime, you have to use another technique (and it'll be slower).

I hope that helps,
Wendell

At 03:25 PM 3/26/2003, you wrote:
Original:
<Categories>
        <Category>
                <Code>A</Code>
                <Description>Airplanes</Description>
        </Category>
        <Category>
                <Code>AA</Code>
                <Description>Airplanes (ARF)</Description>
        </Category>
        <Category>
                <Code>AAE</Code>
                <Description>Airplanes (ARF), Electric</Description>
        </Category>
        <Category>
                <Code>AAG</Code>
                <Description>Airplanes (ARF), Giant</Description>
        </Category>
        <Category>
                <Code>AAP</Code>
                <Description>Airplanes (ARF), Sailplane</Description>
        </Category>
        <Category>
                <Code>B</Code>
                <Description>Boats</Description>
        </Category>
        <Category>
                <Code>BA</Code>
                <Description>Boats (ARF)</Description>
        </Category>
        <Category>
                <Code>BAE</Code>
                <Description>Boats (ARF), Electric</Description>
        </Category>
<Categories>


Final Result - where one letter, two letter, and three letter categories are
nested.


<Categories>
        <LevelOneCategory Code="A" Description="Airplanes">
                <LevelTwoCategory Code="AA" Description="Airplanes (ARF)">
                        <LevelThreeCategory  Code="AAE"
Description="Airplanes (ARF), Electric"/>
                        <LevelThreeCategory  Code="AAG"
Description="Airplanes (ARF), Giant"/>
                        <LevelThreeCategory  Code="AAP"
Description="Airplanes (ARF), Sailplane"/>
                </LevelTwoCategory>
      </LevelOneCategory>
        <LevelOneCategory Code="B" Description="Boats">
                <LevelTwoCategory Code="BA" Description="Boats (ARF)">
                        <LevelThreeCategory  Code="BAE" Description="Boats
(ARF), Electric"/>
                </LevelTwoCategory>
      </LevelOneCategory>
<Categories>


======================================================================
Wendell Piez                            
mailto:wapiez(_at_)mulberrytech(_dot_)com
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


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



<Prev in Thread] Current Thread [Next in Thread>