[PHP/XML/XSL] Alle XML data uit een XML-bestand wordt getoond
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$xslDoc = new DOMDocument();
$xslDoc->load("XSLbestand.xsl");
$xmlDoc = new DOMDocument();
$xmlDoc->load("XMLbestand.xml");
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($xmlDoc);
?>
$xslDoc = new DOMDocument();
$xslDoc->load("XSLbestand.xsl");
$xmlDoc = new DOMDocument();
$xmlDoc->load("XMLbestand.xml");
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($xmlDoc);
?>
Nu werkt dit allemaal goed op 1 ding na. Alle data uit het XML bestand wordt nu getoond op het scherm.
Ik wil juist alleen bepaalde data op het scherm tonen welke zich tussen bepaalde XML-tags bevindt.
De bedoeling is bijvoorbeeld dat op een bepaalde pagina op de website alleen data mbt de DVD's wordt getoond, dus alleen producten welke tussen de <DVD> en </DVD> tags staan. Wat er nu gebeurt is dat alle data uit het XML bestand wordt getoond, ook alles dat tussen <GAMES> tags staat en dat is juist niet de bedoeling.
Ik weet dus alleen niet hoe ik dat moet doen met XSL (of PHP). (De XSL styling moet dus wel blijven werken op de gekozen data uit het XML-bestand.)
Iemand kwam met de volgende suggestie: "Onderdruk de XML elementen die je niet ge-output wil zien met een nieuwe lege XSL template".
Het bovenstaande lijkt me alleen handig in zeer specifieke gevallen, maar niet in mijn geval, want op de ene pagina wil ik een bepaald element wel tonen en op een andere pagina niet. Als ik een element permanent zou onderdrukken op de bovenstaande manier, dan heb ik die flexibiliteit namelijk niet om het XML element te tonen wanneer ik wil.
Een PHP oplossing zoals het volgende zou het ook kunnen laten werken, alleen is het volgende stukje code mijn eigen verzinsel en werkt het niet:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
//Echo alleen alles tussen de DVD-tags
echo $proc->transformToXML($xmlDoc->root[0]->dvd);
//Het bovenstaande stukje code geeft de volgende error:
//Warning: XSLTProcessor::transformToXml() expects parameter 1 to be object, null given
?>
//Echo alleen alles tussen de DVD-tags
echo $proc->transformToXML($xmlDoc->root[0]->dvd);
//Het bovenstaande stukje code geeft de volgende error:
//Warning: XSLTProcessor::transformToXml() expects parameter 1 to be object, null given
?>
Een andere oplossing is een X-Path expressie loslaten op het geladen XML bestand, echter de x-path functie werkt alleen op een SimpleXML object vermoed ik.
Gewijzigd op 01/01/1970 01:00:00 door Graviton
@graviton: misschien heb je hier iets aan? http://us2.php.net/domxpath
@karl hieronder: arrogant??? Hij stelt een vraag! Daarbij heeft ie ook op die andere forums nog geen antwoord gehad, dus waar doe je moeilijk over?
Gewijzigd op 01/01/1970 01:00:00 door Rens nvt
Rens schreef op 08.03.2009 10:09:
@Karl: goed gezien! Echt knap. Maar misschien is het handiger om te proberen de vraag te beantwoorden. Daar schieten de topic starter en andere phphulp lezers meer mee op.
Ik vind het arrogant.
PS: Het lukte me niet om een oplossing te vinden voor dit probleem terwijl de deadline steeds dichterbij komt, vandaar dat ik besloot om op andere forums het probleem ook te posten.
Als goedmakertje zal ik de oplossing ook op elk forum posten, dan heeft elk forum extra content, elk met een oplossing voor het probleem.
Gewijzigd op 01/01/1970 01:00:00 door graviton
graviton schreef op 08.03.2009 02:25:
Een andere oplossing is een X-Path expressie loslaten op het geladen XML bestand, echter de x-path functie werkt alleen op een SimpleXML object vermoed ik.
Je hebt ook DOMXPath: http://nl2.php.net/manual/en/class.domxpath.php
Dus dan krijg je iets in de trant van:
Voorbeeldje die goed werkt:
XML
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<root>
<test>bullshit</test> <!-- XSLT doet hier niks mee -->
<loop>
<value>alleen deze output</value>
</loop>
</root>
<root>
<test>bullshit</test> <!-- XSLT doet hier niks mee -->
<loop>
<value>alleen deze output</value>
</loop>
</root>
XSLT:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:for-each select="root/loop">
<p>output: <xsl:value-of select="value"/></p>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:for-each select="root/loop">
<p>output: <xsl:value-of select="value"/></p>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Resultaat:
Het element <test> zie je nergens terugkomen in de output, wordt niet door de XSLT opgepakt. En zo hoort het ook.
Gewijzigd op 01/01/1970 01:00:00 door Frank -
Je XSLT zou moeten definieren welke data wel/niet wordt geoutput, en op welke manier.
Foutmelding: Warning: DOMDocument::importNode() expects parameter 1 to be DOMNode
De reden voor de foutmelding vermoed ik is dat de methode importNode alleen een DomNode als parameter accepteert, terwijl ik het juist een DOMNodeList als parameter meegeef. De reden daarvoor is dat de xpath->query() methode alleen een DOMNodeList als output geeft. De reden waarom ik het toch op deze manier probeerde is omdat ik geen methode kon vinden in de DOMDocument klasse welke een DOMNodeList kon importeren.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$xslDoc = new DOMDocument();
$xslDoc->load("XSLbestand.xsl");
$xmlDoc = new DOMDocument();
$xmlDoc->load("XMLbestand.xml");
$xpath = new DOMXpath($xmlDoc);
$extractedElements = $xpath->query("/root/dvd");
$xmlDocStripped = new DOMDocument();
$xmlDocStripped->importNode($extractedElements);
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($xmlDocStripped);
?>
$xslDoc = new DOMDocument();
$xslDoc->load("XSLbestand.xsl");
$xmlDoc = new DOMDocument();
$xmlDoc->load("XMLbestand.xml");
$xpath = new DOMXpath($xmlDoc);
$extractedElements = $xpath->query("/root/dvd");
$xmlDocStripped = new DOMDocument();
$xmlDocStripped->importNode($extractedElements);
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($xmlDocStripped);
?>
Gewijzigd op 01/01/1970 01:00:00 door graviton
Je snapt het probleem, maar ik zou juist wel verwachten dat ook <test> ge-output wordt, immers ik geef het hele XMLbestand.xml als input aan de XSLTProcessor in de vorm van een DOMDocument object.
Alles wordt dus ge-output en alleen elementen welke een template aan zich gekoppeld hebben worden gestyled, de rest wordt dan gewoon als ongestylde text ge-output.
@Pholeron:
Hoe zou men dat dan moeten definieren in een .xsl bestand?
Gelieve Niet Bumpen::
Gewijzigd op 01/01/1970 01:00:00 door graviton
graviton schreef op 08.03.2009 21:52:
Nee, dat zou niet best zijn wanneer het zo zou werken. Dan kun je nooit met XSLT een andere XML aanmaken, je krijgt dan altijd de originele XML samen met de nieuwe XML. En daarmee maak je 80% van de XSLT-toepassingen onbruikbaar.@pgFrank:
Je snapt het probleem, maar ik zou juist wel verwachten dat ook <test> ge-output wordt, immers ik geef het hele XMLbestand.xml als input aan de XSLTProcessor in de vorm van een DOMDocument object.
Alles wordt dus ge-output en alleen elementen welke een template aan zich gekoppeld hebben worden gestyled, de rest wordt dan gewoon als unformatted text ge-output.
Je snapt het probleem, maar ik zou juist wel verwachten dat ook <test> ge-output wordt, immers ik geef het hele XMLbestand.xml als input aan de XSLTProcessor in de vorm van een DOMDocument object.
Alles wordt dus ge-output en alleen elementen welke een template aan zich gekoppeld hebben worden gestyled, de rest wordt dan gewoon als unformatted text ge-output.
met XSLT pak je die elementen en attributen die je hebben wilt. De rest doet XSLT niks mee, daar mag XSLT niks mee doen omdat jij ze niet hebt benoemd in jouw XSLT. Je moet expliciet opgeven wat je nodig hebt, alleen dat deel krijg je retour. Wanneer je unformated text retour krijgt, doe je iets fout in je XSLT. Maar omdat we daar nog niks van hebben gezien, kunnen we er ook niks aan veranderen/verbeteren.
pgFrank schreef op 08.03.2009 22:03:
met XSLT pak je die elementen en attributen die je hebben wilt. De rest doet XSLT niks mee, daar mag XSLT niks mee doen omdat jij ze niet hebt benoemd in jouw XSLT. Je moet expliciet opgeven wat je nodig hebt, alleen dat deel krijg je retour. Wanneer je unformated text retour krijgt, doe je iets fout in je XSLT. Maar omdat we daar nog niks van hebben gezien, kunnen we er ook niks aan veranderen/verbeteren.
graviton schreef op 08.03.2009 21:52:
Nee, dat zou niet best zijn wanneer het zo zou werken. Dan kun je nooit met XSLT een andere XML aanmaken, je krijgt dan altijd de originele XML samen met de nieuwe XML. En daarmee maak je 80% van de XSLT-toepassingen onbruikbaar.@pgFrank:
Je snapt het probleem, maar ik zou juist wel verwachten dat ook <test> ge-output wordt, immers ik geef het hele XMLbestand.xml als input aan de XSLTProcessor in de vorm van een DOMDocument object.
Alles wordt dus ge-output en alleen elementen welke een template aan zich gekoppeld hebben worden gestyled, de rest wordt dan gewoon als unformatted text ge-output.
Je snapt het probleem, maar ik zou juist wel verwachten dat ook <test> ge-output wordt, immers ik geef het hele XMLbestand.xml als input aan de XSLTProcessor in de vorm van een DOMDocument object.
Alles wordt dus ge-output en alleen elementen welke een template aan zich gekoppeld hebben worden gestyled, de rest wordt dan gewoon als unformatted text ge-output.
met XSLT pak je die elementen en attributen die je hebben wilt. De rest doet XSLT niks mee, daar mag XSLT niks mee doen omdat jij ze niet hebt benoemd in jouw XSLT. Je moet expliciet opgeven wat je nodig hebt, alleen dat deel krijg je retour. Wanneer je unformated text retour krijgt, doe je iets fout in je XSLT. Maar omdat we daar nog niks van hebben gezien, kunnen we er ook niks aan veranderen/verbeteren.
Maar dat zou dus betekenen dat ik voor mijn XMLbestand.xml vele XSL bestanden moet gaan aanmaken. Want ik gebruik het XMLbestand.xml voor vele pagina's op de website. Dat zou betekenen dat ik voor elke pagina een ander .xsl bestand moet aanmaken, immers alleen XML elementen waar een template aan zit gekoppeld zou dan worden ge-ouput.
Mijn plan was om 1 XML bestand en 1 XSL bestand te hebben voor de hele website.
Gewijzigd op 01/01/1970 01:00:00 door graviton
Quote:
Heel slecht plan, dat is niet te onderhouden en niet te debuggen.Mijn plan was om 1 XML bestand en 1 XSL bestand te hebben voor de hele website.
1 XML zou nog wel kunnen, al vreeeet het geheugen, 1 XSLT is ondoenlijk. Alleen al om het feit dat je ongetwijfeld een hele berg templates en functies nodig zult gaan hebben, wanneer je dat in één bestand zet, wordt het één grote klerezooi. Begin daar niet aan, daar ga je halverwege heel erg veel spijt van krijgen.
Knip de boel op in logische onderdelen en zorg voor een hele goede structuur. Het is net programmeren... ;)
pgFrank schreef op 08.03.2009 22:03:
met XSLT pak je die elementen en attributen die je hebben wilt. De rest doet XSLT niks mee, daar mag XSLT niks mee doen omdat jij ze niet hebt benoemd in jouw XSLT. Je moet expliciet opgeven wat je nodig hebt, alleen dat deel krijg je retour. Wanneer je unformated text retour krijgt, doe je iets fout in je XSLT. Maar omdat we daar nog niks van hebben gezien, kunnen we er ook niks aan veranderen/verbeteren.
Het probleem waar alles uit het XML bestand ge-output werd lijkt nu opgelost. Nu worden inderdaad alleen de xml-elementen ge-output welke een template aan zich gekoppeld hebben. Het vreemde is, is dat ik niets veranderd heb aan het xsl bestand, ik vermoed dat het een toevallige glitch is geweest van de PHP engine bij het toepassen de templates. Nu lijkt alles inderdaad zo te werken zoals je aangeeft.
Echter zit ik nu nog wel met hetzelfde probleem, want zowel alle DVD data wordt ge-output alswel alles Games data, want beide elementgrroepen hebben templates aan zich gekoppeld. Op webpagina X dient alleen de DVD data ge-ouput te worden en op webpagina Y alleen alle Games data.
Ik weet dat ik heb beste dan verschillende XSL bestanden kan aanmaken zoals je aangeeft, maar ik wil het toch op deze manier proberen met 1 XSL bestand, anders ben ik bang dat ik een massa aan verschillende XSL bestanden moet gaan aanmaken. Ik denk dat ik er bijna ben. Alleen die foutmelding vormt nog een probleem. (Geen idee overigens wat voor problemen zich er kunnen voordoen als die opgelost is)
Gewijzigd op 01/01/1970 01:00:00 door graviton
PHP:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$xslDoc = new DOMDocument();
$xslDoc->load("XSLbestand.xsl");
$xmlDoc = new DOMDocument();
$xmlDoc->load("XMLbestand.xml");
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
//Hier pass ik een GET variabele uit de url naar het XSL bestand
$proc->setParameter(null, 'product', $_GET['product']);
echo $proc->transformToXML($xmlDoc);
?>
$xslDoc = new DOMDocument();
$xslDoc->load("XSLbestand.xsl");
$xmlDoc = new DOMDocument();
$xmlDoc->load("XMLbestand.xml");
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
//Hier pass ik een GET variabele uit de url naar het XSL bestand
$proc->setParameter(null, 'product', $_GET['product']);
echo $proc->transformToXML($xmlDoc);
?>
Ook in het XSL bestand definieer ik een "product" parameter. Afhankelijk van de waarde van de parameter kies ik doormiddel van choose en when statements met xpath de juiste range aan elementen en pas op die range de templates toe.
XSL: (De formatting is wat messed up, maar het punt is duidelijk denk ik)
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<xsl:param name="product" />
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$product = 'dvd'">
<xsl:for-each select="/root/dvd">
<xsl:apply-templates/>
</xsl:for-each>
</xsl:when>
<xsl:when test="$product = 'games'">
<xsl:for-each select="/root/games">
<xsl:apply-templates/>
</xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="/dvdElement">
<!-- Hier worden de dvd elementen gestyled -->
</xsl:template>
<xsl:template match="/gamesElement">
<!-- Hier worden de games elementen gestyled -->
</xsl:template>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$product = 'dvd'">
<xsl:for-each select="/root/dvd">
<xsl:apply-templates/>
</xsl:for-each>
</xsl:when>
<xsl:when test="$product = 'games'">
<xsl:for-each select="/root/games">
<xsl:apply-templates/>
</xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="/dvdElement">
<!-- Hier worden de dvd elementen gestyled -->
</xsl:template>
<xsl:template match="/gamesElement">
<!-- Hier worden de games elementen gestyled -->
</xsl:template>
Gewijzigd op 01/01/1970 01:00:00 door graviton