XML og XSLT med Active Server Pages

Microsofts scriptingmiljø på IIS-webserveren byder på robust understøttelse af XML og sprogets følgeteknologier. I denne artikel vises der, hvorledes disse standarder kan udnyttes til at skabe fornuftig separering imellem præsentation, logik og data.

Separering

Microsoft er vældig glad for XML-teknologierne. Det ses blandt andet i firmaets webarkitektur, .Net, som i stor udstrækning bygger på XML og dets følgeteknologier. Men XML giver også masser af mening uden .Net, og i særdeleshed i forbindelse med publicering af data til webbet og andre internetbaserede informationssystemer. De teknikker, der anvendes her i artiklen, bygger i øvrigt på standarder, som også findes i andre programmeringsmiljøer, for eksempel Java. Også dem, der ikke dagligt omgås ASP, burde kunne få noget ud af artiklens eksempel.

På webbet, og i mange andre klient/server-informationssystemer, kan et system eller en applikation separeres i tre dele: Præsentation, logik og data.

Præsentation henfører til systemets grænseflade beregnet til de mennesker, som benytter systemet. Selv om navnet ikke lige siger det, dækker det også over de brugere, som skal putte data ind i systemet.

Logik er de regler, som sammensætter og processerer information, og det er som regel den programmeringskode, der ligger under systemet. Det kan for eksempel også være XSLT, som specificerer hvorledes XML-data kan transformeres til nye sæt af XML-data ved hjælp af en XSLT-processor.

Data giver sig selv: Det er de data, som tilsammen giver de informationer, som brugerne kan udtrække af systemet. Men måden data organiseres på er ikke givet på forhånd. Den almindelige måde at gemme data er at benytte en relationsdatabase, men man skal være opmærksom på, at den måde, man vælger at organisere sine data på, har stor betydning for, hvorledes data kan processeres. Datamodellen har en høj grad af indflydelse på, hvorledes logikken kommer til at se ud, og det kan give et problem: Hvis der er behov for at ændre på datamodellen, kan det resultere i, at der skal foretages store ændringer i logikken.

Der findes andre måder at organisere sine data på end den model, som gives af en relationsdatabase, og XML er en af dem. XML kan give en større grad af frihed i mellem datalag og logik, og på den måde kan applikationens forskellige dele gives en større grad af indbyrdes fleksibilitet end ellers. I mellem logiklaget og præsentationsdelen kan XML også give håndfaste fordele. Ved hjælp af XML-skabeloner, XSLT, kan de færdige data præsenteres på mange forskellige måder til forskellige typer af slutmedier.

Når præsentation, logik og data separeres, bliver det nemmere at foretage ændringer på et af områderne, uden samtidig at skulle ændre på de andre dele. Da det som regel også er forskellige personer, som betjener hver enkelt del, er der også bedre økonomi i separering, da brugerfladedesigneren så at sige ikke behøves at sidde på skødet af programmøren for at udføre sin opgave.

Eksemplet

Eksemplet
I dette simple eksempel vil vi hente data fra forskellige kilder, sætte dem sammen og transformere disse data til god, gammeldags HTML-kode, som en browser kan læse.

Det er der ikke noget sindsoprivende i - eksemplet er faktisk ganske rudimentært. Pointen med dette eksempel er, at en stor del af applikationen er sprog-uafhængigt - den fungerer lige godt i det ene miljø som i det andet.

Den sparsomme kode, som findes i eksemplet, bygger på manipulation af XML-ark via DOM - dokument objekt-modellen. Denne model specificerer et standardiseret API til XML-dokumenter, og den ser altså ens ud, uanset om man benytter ASP, Java eller et andet programmeringsmiljø, som understøtter XML og DOM. DOM hører til i World Wide Web-konsortiets regi og er bredt understøttet som den gængse måde at processere XML-dokumenter programmatisk. Og så er DOM let at forstå og anvende. Ved at benytte DOM bliver koden portabel i højere grad - og når man først har lært teknikkerne, kan de som sagt benyttes i et stort antal programmeringsmiljøer.

Microsofts implementering af DOM er udmærket dokumenteret på Microsoft Developer Network.

Tre flade filer i kodekassen
I dette eksempel, der som sagt er ganske simpelt, henter vi en række XML-filer, der til sammen skal udgøre det færdige dokument, som vi så vil processere med en skabelon og sende til en browser.

Alle filerne kan ses her.

Den første XML-fil indeholder blot stien til de filer, som skal benyttes. I en mere virkelighedsnær situation kunne det være en mere generel angivelse af de datakilder, der skal anvendes.

Filen inputfiler.xml ser således ud:

<?xml version="1.0"?>
<inputkilder>
  <header>
    <fil>header.xml</fil>
  </header>
  <navigation>
    <fil>navigation.xml</fil>
  </navigation>
  <content>
    <fil>content.xml</fil>
  </content>
</inputkilder>

Tekstnoden i <fil>-elementet angiver stien til det dokument, som skal indsættes mellem de andre elementer. På den måde får vi både indhold og den sammenhæng, som indholdet indgår i.

Et lille script

Nu skriver vi et lille script, som indlæser inputfiler.xml, henter de specificerede filer og genererer et nyt XML-dokument af de tre filer. Det er ganske nemt. Først skal den seneste version af Microsofts XML-parser installeres, og det kræver blot at man installerer et lille program, som kan downloades fra Microsoft Developer Network. Den nyeste version hedder 4.0, her i eksemplet benyttede vi version 3, men det burde nu ikke betyde noget.

<SCRIPT LANGUAGE="JSCRIPT" RUNAT="SERVER">

var inputFilListe = "inputfiler.xml";

var xmlDoc = Server.CreateObject("MSXML2.DOMDocument.3.0");
xmlDoc.async = false;
xmlDoc.load(Server.MapPath(inputFilListe));

function hentData() {
  var nodeListe = xmlDoc.selectNodes("//fil/text()");
  for(var i=0; i<nodeListe.length; i++) {
    var aktuelNode = nodeListe.item(i);
    
    var indholdsFil = aktuelNode.nodeValue;

    var xmlIndhold = Server.CreateObject("MSXML2.DOMDocument.3.0");
    xmlIndhold.async = false;
    xmlIndhold.load(Server.MapPath(indholdsFil));

    var xmlIndholdRodNode = xmlIndhold.selectSingleNode("*");
    var moderNode = aktuelNode.parentNode.parentNode;
    moderNode.appendChild(xmlIndholdRodNode);
    
  }

  Response.write(xmlDoc.xml);
  
}

hentData();

</SCRIPT>

I de første par linjer opretter vi et XML-dokumentobjekt. Egenskaben async bestemmer, om scriptet skal fortsætte, selv om filen kun er delvist indlæst, hvilket kan være nyttigt, hvis den hentes fra en fjern kilde. Her sættes den til falsk, da vi blot læser en fil fra harddisken.

Metoden load indlæser XML-filen i vores objekt xmlDoc. Disse tre linjer går igen, hver gang vi skal oprette et XML-dokumentobjekt.

Funktionen hentData() skal nu indsætte de dokumenter, som er specificeret i inputfiler.xml, inde i selve XML-arket. Den første linje

var nodeListe = xmlDoc.selectNodes("//fil/text()");

genererer en liste af noder, elementer i XML-dokumentet, ud fra det kriterie, som er angivet i streng-argumentet. Streng-argumentet er et såkaldt XPath-udtryk. XPath er en standard til at navigere rundt i XML-dokumenter med. XML-dokumenter er træstrukturer, ligesom websider, og XPath minder meget om de adresser, man benytter på web. Denne artikel kan desværre ikke gå i dybden med XPath, men udtrykket her, "//fil/text()", betyder: Find alle tekst-noder, der befinder sig under et <fil>-element. Det giver os de tre filnavne i inputfiler.xml som resultat.

Derefter har vi en løkke, som gennemløber listen. Linjen

var indholdsFil = aktuelNode.nodeValue;

sætter variablen indholdsFil til det filnavn, som er angivet i hver af fil-elementerne i inputfiler.xml.

De næste tre linjer har vi set før - de indlæser det XML-dokument, hvis filnavn vi lige har udtrukket af inputfiler.xml, og gemmer det i objektet xmlIndhold.

Nu skal vi indlejre det XML-dokument, vi netop har indlæst, med det XML-dokument, som vi arbejder med. Vi indlæser xmlInhold som en node, et deltræ om man vil, i linjen

var xmlIndholdRodNode = xmlIndhold.selectSingleNode("*");

Ligesom tidligere finder vi her vores node ved hjælp af XPath. Argumentet "*" (asterisk) betyder blot "alle elementer".

Nu skal vi indsætte det nye træ i det gamle. I det gamle dokument peger vores variabel aktuelNode på en tekstnode (vores filnavn fra før), så vi skal bakke tilbage i træet, til vi lander i elementet lige før <fil>. Vi skal altså finde aktuelNode's oldeforældre. Og det er jo forældrenodens forældrenode:

var moderNode = aktuelNode.parentNode.parentNode;

Og så tilføjer vi det nye træ i det gamle:

moderNode.appendChild(xmlIndholdRodNode);

På ydersiden af løkken tester vi nu, hvad vi egentlig fik ud af det hele, med linjen

Response.write(xmlDoc.xml);

Det kunne godt se ud som om det var et filnavn, der står som argument, men det er det ikke. Det er xmlDoc-objektet, udskrevet som xml-tekst. Og det ser sådan ud, i Internet Explorer:

Det færdige XML-dokument. Dokumentet indeholder kun struktur og ingen præsentationselementer.

Nu har vi alle de elementer, vi skal bruge for at opbygge hele siden, i vores XML-dokument. Nu kan vi så opbygge de dokumenter, der skal sendes til klienterne. Man kunne forestille sig en skabelon til gamle browsere, en til nye browsere, en som genererer WML-sider til WAP-telefoner og meget mere.

Stil

Stil skal der til
Det næste skridt er altså at formatere vores XML. Her bruger vi blot en enkel skabelon, som genererer almindelig HTML-kode. Det gøres med XSLT, og det har vi gennemgået i en tidligere artikel her på kanalen.

Selve scriptet er lige ud af landevejen:

function transformerOgUdskriv() {
  var xsltSkabelon = "stylesheet.xsl";

  var xmlStylesheet = Server.CreateObject("MSXML2.DOMDocument.3.0");
  xmlStylesheet.async = false;
  xmlStylesheet.load(Server.MapPath(xsltSkabelon));
  
  var strValue = xmlDoc.transformNode(xmlStylesheet);

  Response.write(strValue);

}

Vi indlæser XSLT-dokumentet på samme vis som de øvrige XML-dokumenter. Så er det blot at benytte metoden transformNode på vores xmlDoc-objekt fra før og udskrive resultatet til browseren.

Så får vi dette resultat:

Kønt er det ikke, så vi fjerner den grimme tabelramme ved at modificere en anelse i XSLT-arket, og så smækker vi et CSS-stylesheet oven i hatten:

Der kan nørkles videre med XSLT- og CSS-ark - men det kræver ikke ændringer i programkoden. Og bare rolig - teknologien kan også klare æ, ø og å.

XML løser ikke alle problemer, men forhåbentlig gav eksemplet indtryk af, at man kan opnå en hel del med få linjers kode og med en høj grad af separering af præsentation, logik og data.

Læses lige nu

    Forsvarsministeriets Materiel- og Indkøbsstyrelse

    Selvstændig IT-sagsbehandler søges til dynamisk virksomhed i Hvidovre

    Midtjylland

    Netcompany A/S

    Microsoft Operations Engineer

    Midtjylland

    Netcompany A/S

    Data Management Consultant

    Midtjylland

    KMD A/S

    Konsulent til KMD Health & Social

    Københavnsområdet

    Computerworld Events

    Vi samler hvert år mere end 6.000 deltagere på mere end 70 events for it-professionelle.

    Ekspertindsigt – Lyt til førende specialister og virksomheder, der deler viden om den nyeste teknologi og de bedste løsninger.
    Netværk – Mød beslutningstagere, kolleger og samarbejdspartnere på tværs af brancher.
    Praktisk viden – Få konkrete cases, værktøjer og inspiration, som du kan tage direkte med hjem i organisationen.
    Aktuelle tendenser – Bliv opdateret på de vigtigste dagsordener inden for cloud, sikkerhed, data, AI og digital forretning.

    It-løsninger | København Ø

    Automatisering med Copilot & Agentic AI

    Høst viden og erfaringer fra andre om, hvordan Copilot og Agentic AI i praksis kan skabe værdi og fleksibilitet i din organisation.

    Sikkerhed | Online

    Erfaringer fra frontlinjen: Sådan ændrer trusselsbilledet sig

    Kort og fokuseret digitalt event: Erfaren frontkæmper fra den digitale sikkerhedsverden giver dig overblik og konkrete anbefalinger til det aktuelle trusselsbillede.

    Andre events | Valby

    CIO Challenges: Teknologi, transformation og ledelse der flytter forretningen

    Hvordan moderniseres en it-platform uden legacy? Hvordan skaber man nye AI‑ og cloud‑drevne forretningsmodeller – uden at miste medarbejdere eller brugere undervejs? På CIO Challenges 2025 får du hands‑on erfaringer fra fire danske CIO’er, der...

    Se alle vores events inden for it

    Navnenyt fra it-Danmark

    Netip A/S har pr. 15. september 2025 ansat Peter Holst Ring Madsen som Systemkonsulent ved netIP's kontor i Holstebro. Han kommer fra en stilling som Team Lead hos Thise Mejeri. Nyt job
    Sebastian Rübner-Petersen, 32 år, Juniorkonsulent hos Gammelbys, er pr. 1. september 2025 forfremmet til Kommunikationskonsulent. Han skal fremover især beskæftige sig med Projektledelse, kommunikationsstrategier og implementering af AI. Forfremmelse
    Norriq Danmark A/S har pr. 1. oktober 2025 ansat Rasmus Stage Sørensen som Operations Director. Han kommer fra en stilling som Partner & Director, Delivery hos Impact Commerce. Han er uddannet kandidat it i communication and organization på Aarhus University. Han har tidligere beskæftiget sig med med at drive leveranceorganisationer. Nyt job

    Rasmus Stage Sørensen

    Norriq Danmark A/S