Webudviklerens drøm: Cross-browser uden tårer

Med XML, XSLT og CSS er det ingen sag at levere dynamisk indhold i så forskellige formater som HTML4, HTML3.2, XHTML1.0 og alt muligt andet. I artiklen vises hvordan det gøres med få liniers kode.

Tre slags uddata

Vi har tidligere gennemgået teknologierne XML, XSLT, CSS, HTML4, HTML3.2, XHTML1.0 i adskillige artikler. I denne artikel viser vi helt konkret, hvorledes XML-baseret inddata sammen med XSLT-ark hurtigt og nemt kan generere uddata så forskelligt som HTML3.2 til gamle browsere, XHTML til moderne browsere og en version til håndholdte - alt sammen ud fra samme inddata.

Vi har i en tidligere artikel gennemgået, hvorledes XML transformeres med XSLT.

Som udgangspunkt har vi et XML-dokument med en eller anden form for indhold. Her i eksemplet er det en af vores egne artikler, der danner inddata, men det kunne lige så godt være produktinformation eller alt mulig andet dynamisk generet indhold.


<?xml version="1.0" encoding="ISO-8859-1"?>
<side>
  <titel>Comanche - administration af Apache</titel>
  <overskrift>Grafisk administration af Apache</overskrift>
  <manchet>
    Fuldblods Unix-hajer redigerer deres
    konfigurationsfiler i Vi og Emacs.
  </manchet>
  <tekst>
    <afsnit>Comanche kan downloades fra
      www.covalent.net og findes i
      forskellige versioner.</afsnit>
    <afsnit>Comanche har sit udspring i
      Apache GUI-projektet, der
      startede i 1997.</afsnit>
  </tekst>
</side>

Først skriver vi et XSLT-ark, til ældre HTML3.2 browsere. Her formaterer vi al tekst med gammeldags <FONT>-tags.


<xsl:template match="overskrift">
  <p><font face="arial,helvetica" size="3"><b>
      <xsl:value-of select="." />
  </b></font></p>
</xsl:template>

Hele arket kan ses sidst i denne artikel.

Derefter er det simpelt at skrive et XSLT-ark til XHTML baseret på et CSS-ark. Vi tager simpelthen vores ark til HTML3.2-browsere og erstatter alle formateringtags med CSS-klasser.

Toppen af arket ser således ud:


<xsl:template match="side">
<html>
<head>
  <title><xsl:value-of select="titel" /></title>
  <link rel="stylesheet"
  type="text/css"
  href="xhtml_styles.css" />
</head>
<body>

<xsl:apply-templates />

</body>
</html>
</xsl:template>

Og de enkelte dele af XML-arket formateres således:


<xsl:template match="overskrift">
  <h1 class="overskrift">
    <xsl:value-of select="." />
  </h1>
</xsl:template>

Hele arket kan ses sidst i artiklen.

Til sidst laver vi en version til PDA-tjenesten AvantGo, hvor brugere af lommecomputere baseret på PalmOS og Windows CE kan downloade offline-versioner af webindhold. Der er stort set blot tale om en neddroslet version af vores HTML3.2-ark. Mere information kan findes på AvantGo's side for udviklere. Meta-tagget <meta name="HandheldFriendly" content="True" /> er det vigtigeste i denne sammenhæng - det fortæller, at dokumentet er optimeret til håndholdt udstyr:


<xsl:template match="side">
<html>
<head>
  <meta name="HandheldFriendly" content="True" />
  <title><xsl:value-of select="titel" /></title>
</head>
<body>

<xsl:apply-templates />

</body>
</html>
</xsl:template>

Og de enkelte dele formateres som gammeldags HTML, men uden <FONT>-tags:


<xsl:template match="overskrift">
  <h1 class="overskrift">
    <xsl:value-of select="." />
  </h1>
</xsl:template>

Nu da vi har de tre relevante XSLT-dokumenter, er det bare at sende de rigtige versioner afsted til de rigtige brugeragenter.

Browserdetektering

Vores uddata til håndholdte lægger vi på en særskilt adresse, for der skal brugerne alligvel navigere frem til sitet på egen hånd. Men alle de almindelige browsere kommer ind på den samme adresse, så her skal vi skelne imellem dem der kan håndtere XHTML og CSS, og dem der skal have gammeldags HTML3.2.

Det gøres ved at kigge på browserens navn og versionsnummer. Netscape og Internet Explorer er CSS-kapable i versioner 4 og opefter, og Opera for version 5 og op. Så disse versioner får vores CSS-formaterede XHTML1 version. I PHP gøres det for eksempel som vist herunder, forudsat at PHP er kompileret med XSLT-udvidelsen Sablotron. I eksemplet har vi kilde-xml-data liggende i en variabel ved navn $input.


// Vi ser, hvad for en browser, brugeren benytter

$ua = get_browser();

$browser_xhtml_capable =
  (( $ua->browser == "Netscape" )
  && ( $ua->version >= 4 ))
||
  (($ua->browser == "Internet Explorer" )
  && ( $ua->version >= 4 ))
||
  (( $ua->browser == "Opera" )
  && ( $ua->version >= 5 ));

if($browser_xhtml_capable) {
  // Disse browsere kan håndtere CSS,
  // så de får vores XHTML1.0-formaterede
  // dokument:
  $filename =
  "/usr/local/apache/htdocs/xml/xhtml.xsl";
} else {

  // Øvrige browsere får HTML3.2-versionen:
  $filename =
  "/usr/local/apache/htdocs/xml/html32.xsl";
}

// Så åbner vi det relevante XSLT-dokument...

$fd = fopen ($filename, "r");
$xsl_sheet = fread ($fd, filesize ($filename));
fclose ($fd);

// ...og processerer uddata:

$result = @xslt_process($xsl_sheet, $input,  $output);

if($result) {
  echo $output;
} else {
  echo "Der opstod desværre følgende fejl: "
  .xslt_error(xslt_errno());
}

I ASP skal man benytte objektet MSXML2.DOMDocument, og det foregår - i grove rids - som vist herunder i dialekten JScript, hvor input og filename er identisk med vores PHP-variabler $input og $filename:

¨
// Indlæs XML-inddata
var oSource = Server.CreateObject("MSXML2.DOMDocument.3.0");
oSource.async = false;
oSource.loadXML(input);

// Hent det rigtige XSLT-ark
var oStylesheet = Server.CreateObject("MSXML2.DOMDocument.3.0");
oStylesheet.async = false;
oStylesheet.load(filename);

// Processor uddata, og send det til klienten:
output = oSource.transformNode(oStylesheet);

Response.write(output);

Som det forhåbentligt kan ses, er det nemt at generere uddata til forskellige klienttyper. Ligeledes er der store fordele at hente når sitet skal redesignes, og når der skal fabrikeres uddata til nye klienttyper.

Koden bag XSL-arkene

XML-inddata blev vist først i artiklen, men man skal huske, at data skal gemmes som Unicode - ellers kan XSLT-processoren løbe sur i æ, ø og å.

Arkene kan testes på statisk vis i Internet Explorer ved at gemme XSL-arkene og XML-kilden som flade filer, og derefter tilføje denne streng som anden linie i XML-arket:

<?xml-stylesheet type="text/xsl" href=" HTML32.xsl" ?>

- hvor href-attributten skal pege på det XSL-ark, man ønsker at teste.

XSL-arket til HTML3.2-browserne ser sådan ud:


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:template match="/">
  <xsl:apply-templates />
</xsl:template>

<xsl:template match="side">
<html>
<head>
   <title><xsl:value-of select="titel" /></title>
</head>
<body>

<xsl:apply-templates />

</body>
</html>
</xsl:template>

<xsl:template match="overskrift">
  <p><font face="arial,helvetica" size="3"><b><xsl:value-of select="." /></b></font></p>
</xsl:template>

<xsl:template match="manchet">
  <p><font face="arial,helvetica" size="2"><b><xsl:value-of select="." /></b></font></p>
</xsl:template>

<xsl:template match="tekst">
  <xsl:apply-templates />
</xsl:template>

<xsl:template match="afsnit">
  <p><font face="arial,helvetica" size="2"><xsl:value-of select="." /></font></p>
</xsl:template>

<xsl:template match="titel">
</xsl:template>

</xsl:stylesheet>

XSL-arket til XHTML-browserne ser således ud:


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:template match="/">
    <xsl:apply-templates />
</xsl:template>

<xsl:template match="side">
  <html>
  <head>
    <title><xsl:value-of select="titel" /></title>
    <link rel="stylesheet" type="text/css" href="xhtml_styles.css" />
  </head>
  <body>

  <xsl:apply-templates />
  
  </body>
  </html>
</xsl:template>

<xsl:template match="overskrift">
    <h1 class="overskrift"><xsl:value-of select="." /></h1>
</xsl:template>

<xsl:template match="manchet">
    <p class="manchet"><xsl:value-of select="." /></p>
</xsl:template>

<xsl:template match="tekst">
    <xsl:apply-templates />
</xsl:template>

<xsl:template match="afsnit">
    <p class="broedtekst"><xsl:value-of select="." /></p>
</xsl:template>

<xsl:template match="titel">
</xsl:template>

</xsl:stylesheet>

Til sidst er der XSL-arket til AvantGo-tjenesten:


<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:template match="/">
  <xsl:apply-templates />
</xsl:template>

<xsl:template match="side">
  <html>
  <head>
      <meta name="HandheldFriendly" content="True" />
    <title><xsl:value-of select="titel" /></title>
  </head>
  <body>

  <xsl:apply-templates />
  
  </body>
  </html>
</xsl:template>

<xsl:template match="overskrift">
  <h1><xsl:value-of select="." /></h1>
</xsl:template>

<xsl:template match="manchet">
  <p><b><xsl:value-of select="." /></b></p>
</xsl:template>

<xsl:template match="tekst">
  <xsl:apply-templates />
</xsl:template>

<xsl:template match="afsnit">
  <p><xsl:value-of select="." /></p>
</xsl:template>

<xsl:template match="titel">
</xsl:template>

</xsl:stylesheet>

Netcompany A/S

Linux Operations Engineer

Midtjylland

Netcompany A/S

Operations Engineer til drift af Infrastruktur

Københavnsområdet

Capgemini Danmark A/S

Open Application (Denmark)

Københavnsområdet

Event: Cyber Security Festival 2026

Sikkerhed | København

Mød Danmarks skrappeste it-sikkerhedseksperter og bliv klar til at planlægge og eksekvere en operationel og effektiv cybersikkerhedsstrategi, når vi åbner dørene for +1.700 it-professionelle. Du kan glæde dig til oplæg fra mere end 70 talere og møde mere end 50 leverandører over to dage.

18 & 19 november 2026 | Gratis deltagelse

Navnenyt fra it-Danmark

Renewtech ApS har pr. 1. marts 2026 ansat Emil Holme Fisker som Customer Service Specialist. Han skal især beskæftige sig med at levere høj kvalitets kundeservice og hjælpe Renewtechs kunder med at få de rette løsninger til deres behov. Han kommer fra en stilling som Key Account Manager hos Camro A/S. Han er uddannet som salgselev hos Camro A/S. Han har tidligere beskæftiget sig med at udvikle gode kunderelationer, opsøgende salg og udvikling af salgsaktiviteter. Nyt job

Emil Holme Fisker

Renewtech ApS

Alexander Hoffmann, SVP, Technology & IT hos GlobalConnect, er pr. 1. maj 2026 forfremmet til EVP, Tech, IT & Security. Han skal fremover især beskæftige sig med at lede den fortsatte udvikling af en mere integreret og software-drevet infrastrukturplatform. Forfremmelse

Alexander Hoffmann

GlobalConnect

Mohamed El Haddaoui, er pr. 7. april 2026 ansat hos Dafolo A/S som IT-systemudvikler. Han skal især beskæftige sig med udviklingsopgaver relateret til Brugerklubben SBSYS. Han er nyuddannet datamatiker og har erfaring med udvikling af REST API'er og integreret databaser. Nyt job

Mohamed El Haddaoui

Dafolo A/S

Sharp Consumer Electronics har pr. 1. april 2026 ansat Daniel Eriksson som salgsdirektør for de nordiske lande. Han skal især beskæftige sig med at accelerere virksomhedens vækst i Norden. Han kommer fra en stilling som nordisk salgsdirektør hos Hisense. Han har tidligere beskæftiget sig med detailhandel, kommerciel strategi og markedsudvidelser med bemærkelsesværdige resultater til følge. Nyt job

Daniel Eriksson

Sharp Consumer Electronics