!

Dette materialet blir ikke lenger vedlikeholdt. Du vil finne oppdatert materiale på siden: http://borres.hiof.no/wep/

XSLT
Børre Stenseth
XSL > XSLT > Olympiade >XML2XML

Transformasjon fra XML til XML

Hva
Demonstrerer noen enkle XML -> XML transformasjoner

I denne modulen skal vi lage to forskjellige transformasjoner med utgangspunkt i våre olympiske data. Vi skal ekstrahere 100m resultatene og vi skal lage en restrukturering av fila til en flatere struktur.

Bare 100m

Vi ønsker å ekstrahere 100m resultatene og lage en ny xml-fil som er organisert på en litt annen måte. En skisse:

  <Sprint-100m>
   <OlympicGame place="Atlanta -  1996">
      ... athlets som før men bare fra 100m...
   </OlympicGame>
   <OlympicGame place="Barcelona -  1992">
      ... athlets som før men bare fra 100m ...
   </OlympicGame>
  </Sprint-100m>
  

Vi ønsker altså:

  • Introdusere en ny dokumenttype: Sprint-100m
  • Endre, forenkle, attributtliste til elementet:OlympicGame
  • Ekstrahere bare 100m resultatene

Dokumenttypen vil vi ha slik:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!ELEMENT OlympicGame (athlet+)>
<!ATTLIST OlympicGame
    place CDATA #REQUIRED
>
<!ELEMENT Sprint-100m (OlympicGame+)>
<!ELEMENT athlet (name, nation, result)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT nation (#PCDATA)>
<!ELEMENT result (#PCDATA)>

Skjematisk gjør vi følgende:

XML2XML
Fra XML til XML

Selve transformasjonsjobben, T, utføres i et program. For dette eksperimentet kan vi bruke XMLSpy, eller vi kan bruke en nettleser som transformaerer direkte.

Vi skriver en enkel transformasjonsfil, en olymp3.xsl, som beskriver denne transformasjonen:

<?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"  
              doctype-system="olymp100.dtd" 
              encoding="UTF-8" />
 
<xsl:template match="/">
<Sprint-100m>
<xsl:for-each select="IOC/OlympicGame">
   <OlympicGame>
      <xsl:attribute name="place">
       <xsl:value-of select="@place"/>
      <xsl:text> -  </xsl:text>
       <xsl:value-of select="@year"/>
      </xsl:attribute>
      <xsl:for-each select="event">
            <xsl:if test="@dist[.='100m']"> 
         <xsl:for-each select="athlet">
            <xsl:copy-of select="."/>
         </xsl:for-each>
         </xsl:if>
      </xsl:for-each>
   </OlympicGame>
</xsl:for-each>
</Sprint-100m>
</xsl:template>
 
</xsl:stylesheet>

Det er mange måter å gjøre dette på. Her er valgt en eksplisitt form som ligner det resonnementet vi ville bruke i et tradisjonelt språk.

La oss først se litt på linjene i headingen:

  
1<?xml version="1.0" encoding="utf-8"?>
2 <xsl:stylesheet  version="1.0"
                   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3 <xsl:output method="xml" omit-xml-declaration="no"  
              doctype-system="olymp100.dtd"/>
  
  

Linje 1 forteller oss at xsl-fila faktisk er en xml-fil ! Linje 2 forteller at vi skal lage et stilsett med versjon 1 av xsl og vi definerer et namespace. Linje 3 sier at vi skal produsere xml (alternativene er html eller text), at vi vil ha xml-angivelse i resultatet, og endelig at det vi produserer skal være et dokument av typen olymp100.dtd. Vi skal altså kunne validere resultatet av transformasjonen mot en dtd-fil som er annerledes enn utgangspunktet.

Så ser vi på innmaten av transformasjonen, templaten:


4  <xsl:template match="/">
5  <Sprint-100m>
6  <xsl:for-each select="IOC/OlympicGame">
7   <OlympicGame>
8      <xsl:attribute name="place">
9       <xsl:value-of select="@place"/>
10      <xsl:text> -  </text>
11      <xsl:value-of select="@year"/>
12      </attribute>
13      <xsl:for-each select="event">
14            <xsl:if test="@dist[.='100m']"> 
15         <xsl:for-each select="athlet">
16            <xsl:copy-of select="."/>
17         </for-each>
18         </if>
19      </for-each>
20   </OlympicGame>
21 </for-each>
22 </Sprint-100m>
23 </template>

Linje 4 - 23 beskriver en template som skal ta fatt i ytterste element i kildedokumnetet, match="/">. Linjene 5 og 22 produserer start og slutt tag for rotelmentet i det dokumentet vi skal produsere. Linjene 6 og 21 avgrenser en løkke over alle olympiske leker og linje 7 og 20 produserer tager for hver olympiade.

Linje 8 tar fatt i attributten place til elementet og linjene 9 - 12 produserer den nye attributten på grunnlag av de to gamle, place og year. I linje 13 starter en løkke over alle øverlser, events, og for de som tilsvarer den geneskapen at deres dist-attributt er lik 100m kopierer vi alle løperne, athlets.

Vi kopler xsl-fila til xml-fila ved følgende linje i toppen på xml-fila, all_results3.xml:

  <?xml version="1.0" encoding="utf-8"?>
  <!DOCTYPE IOC SYSTEM "olymp.dtd" >
  <?xml-stylesheet code="text/xsl" href="olymp3.xsl"?>
  <IOC>
  ...

  
Resultat http://www.it.hiof.no/~borres/dw/olymp/ol2xml/results100m.xml

Vi oppnår nøyaktig samme resultat med transformasjonen nendenfor. Denne er skrevet med 3 templates og er et bedre alternativ.

<?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"  
              doctype-system="olymp100.dtd" 
              encoding="UTF-8" 
              indent="yes"/>
 
<xsl:template match="/">
    <Sprint-100m>
    <xsl:apply-templates select="IOC/OlympicGame"/>    
    </Sprint-100m>
</xsl:template>
 
<xsl:template match="//OlympicGame">
 <OlympicGame>
      <xsl:attribute name="place">
       <xsl:value-of select="@place"/>
      <xsl:text> -  </xsl:text>
       <xsl:value-of select="@year"/>
      </xsl:attribute>
      <xsl:apply-templates select="event[@dist='100m']"/>
   </OlympicGame>
</xsl:template>
 
<xsl:template match="//athlet">
            <xsl:copy-of select="."/>
</xsl:template>
 
</xsl:stylesheet>

Reorganisering

her tar vi for oss materialet og reorganiserer den slik:

XML2XML2
Reorganisering av olympiske data

Det betyr at vi skal gå fra:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!ELEMENT IOC (OlympicGame+)>
<!ELEMENT OlympicGame (event+)>
<!ATTLIST OlympicGame
    place CDATA #REQUIRED
    year CDATA #REQUIRED
>
<!ELEMENT athlet (name, nation, result)>
<!ELEMENT event (athlet+)>
<!ATTLIST event
    dist (100m | 200m | 400m) #REQUIRED
>
<!ELEMENT name (#PCDATA)>
<!ELEMENT nation (#PCDATA)>
<!ELEMENT result (#PCDATA)>

til

<?xml version="1.0" encoding="ISO-8859-1"?>
<!ELEMENT IOC (event+)>
<!ELEMENT athlet (name, nation, result)>
<!ELEMENT event (athlet+)>
<!ATTLIST event
    dist (100m | 200m | 400m) #REQUIRED
    place (Atlanta | Barcelona | Sidney | Athens | Beijing | London) #REQUIRED
    year (1992 | 1996 | 2000 | 2004 | 2008 | 2012) #REQUIRED
>
<!ELEMENT name (#PCDATA)>
<!ELEMENT nation (#PCDATA)>
<!ELEMENT result (#PCDATA)>

Transformasjonsfila er i sin helhet slik:

<?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" 
    doctype-system="olympreorg.dtd" encoding="UTF-8"/>
 
<xsl:template match="/">
<IOC>
   <xsl:apply-templates select="/IOC/OlympicGame/event"/>
</IOC>
</xsl:template>
 
<xsl:template match="event">
    <xsl:element name="event">
      <xsl:attribute name="dist">
         <xsl:value-of select="@dist"/>
      </xsl:attribute>
      <xsl:attribute name="place">
         <xsl:value-of select="ancestor::OlympicGame/@place"/>
      </xsl:attribute>
      <xsl:attribute name="year">
         <xsl:value-of select="ancestor::OlympicGame/@year"/>
      </xsl:attribute>
      <xsl:apply-templates select="athlet"/>
   </xsl:element>
</xsl:template>
 
<xsl:template match="athlet">
 <xsl:copy-of select="."/>
</xsl:template>
 
</xsl:stylesheet>
Resultat http://www.it.hiof.no/~borres/dw/olymp/ol2xml/reorg_results.xml
Referanser

Aktuelle filer i eksempelet er siterte i teksten:

Vedlikehold
Børre Stenseth, mai 2006
( Velkommen ) XSL > XSLT > Olympiade >XML2XML ( XML2TXT )