XSLT
XSLT
Børre Stenseth
Olympiade >XML2XML

Transformasjon fra XML til XML

Hva

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 at vi kan validere:

_scheme100.xsd

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.

Resultat https://borres.hiof.no/wep/xslt/ol/xml2xml/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:

_../olymp.xsd

til en versjon som også har mindre detaljeringsgrad

_schemereorg.xsd

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 https://borres.hiof.no/wep/xslt/ol/xml2xml/reorg_results.xml
Olympiade >XML2XML