Transformasjon fra XML til XML
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 restruktureing 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:
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="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" doctype-system="olymp100.dtd" encoding="ISO-8859-1" /> <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="@track[.='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="ISO-8859-1"?> 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 utgngspunktet.
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> - </xsl:text> 11 <xsl:value-of select="@year"/> 12 </xsl:attribute> 13 <xsl:for-each select="event"> 14 <xsl:if test="@track[.='100m']"> 15 <xsl:for-each select="athlet"> 16 <xsl:copy-of select="."/> 17 </xsl:for-each> 18 </xsl:if> 19 </xsl:for-each> 20 </OlympicGame> 21 </xsl:for-each> 22 </Sprint-100m> 23 </xsl: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 track-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="ISO-8859-1"?> <!DOCTYPE IOC SYSTEM "olymp.dtd" > <?xml-stylesheet type="text/xsl" href="olymp3.xsl"?> <IOC> ...
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="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" doctype-system="olymp100.dtd" encoding="ISO-8859-1" 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[@track='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:
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
track (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
track (100m | 200m | 400m) #REQUIRED
place (Atlanta | Barcelona | Sidney | Athens) #REQUIRED
year (1992 | 1996 | 2000 | 2004) #REQUIRED
>
<!ELEMENT name (#PCDATA)>
<!ELEMENT nation (#PCDATA)>
<!ELEMENT result (#PCDATA)>
Transformasjonsfila er i sin helhet slik:
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" doctype-system="olympreorg.dtd" encoding="ISO-8859-1"/> <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="track"> <xsl:value-of select="@track"/> </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>