SAX gebruiken in PHP
1 bericht
• Pagina 1 van 1
SAX gebruiken in PHP
Inleiding
Soms is het handig om XML in te lezen binnen je PHP-script, bijvoorbeeld voor het laden van instellingen of data, bijvoorbeeld in de vorm van RSS.
Om de XML te parsen zijn er verschillende mogelijkheden; je zou bijvoorbeeld met de stringfuncties van PHP de XML-string opdelen in tokens die je vervolgens analyseert.
Een andere mogelijkheid is het gebruik van speciale XML-parser, die echt is ontworpen voor het gebruik met XML.
Eén van die XML-parsers is SAX (Simple API for XML). Dit is een zogenaamde event-based API, wat inhoudt dat de parser een door de gebruiker gespecificeerde functie aanroept wanneer een parsing-event - bijvoorbeeld het begin of het eind van een element - optreedt. Dit geeft de gebruiker de mogelijkheid om bij de start van een bepaald element bijvoorbeeld de naam van dit element af te drukken, maar natuurlijk ook om nog veel leukere dingen te doen, zoals ik in het voorbeeld in dit artikel zal laten zien.
Het opzetten van de parser
De SAX-parser kan met enkele eenvoudige opdrachten worden geïnitialiseerd. Allereerst moeten we een paar functies schrijven om de optredende events af te handelen.
PHP
$parser refereert aan de parser die de functie heeft aangeroepen, $elementname is de naam van het element en $attributes is een array met alle attributen en hun waarden.
PHP
$parser refereert weer aan de parser die de functie heeft aangeroepen en $elementname is de naam van het element dat gesloten wordt.
PHP
Deze functie wordt gebruikt wanneer de parser$parser een karakter tegenkomt buiten tags om. Dit karakter wordt doorgegeven in de parameter $data .
Vervolgens moeten wij de parser aanmaken met de functiexml_parser_create , en wel op de volgende manier:
PHP
Aanxml_parser_create kan de facultatieve parameter encoding worden toegevoegd, die de volgende formaten mag bevatten:
PHP
Bijvoorbeeld:
PHP
In de PHP-documentatie wordt casefolding als volgt omschreven:
In goed Nederlands: als de optie casefolding aan staat, worden alle elementnamen vervangen door hun equivalent in kapitalen; het elementblaat zal dan BLAAT heten. Ik heb zelf XML_OPTION_CASE_FOLDING meestal op 0 (uit) staan.
Er zijn nog meer mogelijke instellingen, welke je op de website van PHP kunt vinden.
Nu we een parser hebben aangemaakt en de instellingen naar onze smaak hebben gewijzigd, zullen we aangeven welke functies de parser moet gebruiken tijdens het parsen. Dit gebeurt - onder andere - door middel van de volgende functies:
PHP
Waarin$parser refereert aan de te gebruiken parser en de volgende parameters de namen van de te gebruiken functies zijn: startElement en endElement voor de elementen en characterData voor de overige karakters.
Verder is het mogelijk om voor bijvoorbeeld processinginstructions ook handlers te selecteren (= functies specificeren). Kijk in de documentatie op de website van PHP welke handlers er allemaal mogelijk zijn.
Na het aangeven van de functies is het tijd voor het echte werk: we geven de parser de opdracht om daadwerkelijk te parsen, door middel van de volgende functie:
PHP
Hierin is$parser weer een referentie aan de te gebruiken parser. $text is een XML-string met bijvoorbeeld de inhoud van een bepaald bestand.
Na het parsen is het netjes om de parser op te ruimen, dit doen we door de functiexml_parser_free() aan te roepen:
PHP
Voorbeeld
In het volgende voorbeeld gaan we een receptenboekje in XML-formaat proberen te parsen met behulp van een PHP-script. In het script heb ik gebruik gemaakt van een klasse Recipe, die een recept beschrijft. Dit is echter niet noodzakelijk voor het inlezen van een document, maar ik vond het hier wel op zijn plaats.
Het PHP-script (recepten.php):
PHP
Het XML-bestand (recepten.xml):
XML
Event-based versus tree-based
Er zijn, strikt genomen, twee verschillende API's voor het parsen van XML: DOM (Document Object Model) en SAX.
DOM parst het document in een objectgeoriënteerde tree, zodat je een ouderelement heeft die een array met kindelementen bevat die op hun beurt misschien ook weer kinderelementen bevatten.
SAX parst het document op een event-based manier. Dit heeft als groot voordeel dat het mogelijk is een groot document, bijvoorbeeld een XML-bestand van 100 MegaByte, te parsen - zonder dat het gehele document in het geheugen hoeft te worden geplaatst.
In tegenstelling tot SAX biedt DOM wel de mogelijkheid om XML-bestanden niet alleen in te lezen, maar ook aan te maken.
Het is natuurlijk ook mogelijk om met behulp van een SAX-parser een objectgeoriënteerde tree aan te maken.
Nuttige links
Soms is het handig om XML in te lezen binnen je PHP-script, bijvoorbeeld voor het laden van instellingen of data, bijvoorbeeld in de vorm van RSS.
Om de XML te parsen zijn er verschillende mogelijkheden; je zou bijvoorbeeld met de stringfuncties van PHP de XML-string opdelen in tokens die je vervolgens analyseert.
Een andere mogelijkheid is het gebruik van speciale XML-parser, die echt is ontworpen voor het gebruik met XML.
Eén van die XML-parsers is SAX (Simple API for XML). Dit is een zogenaamde event-based API, wat inhoudt dat de parser een door de gebruiker gespecificeerde functie aanroept wanneer een parsing-event - bijvoorbeeld het begin of het eind van een element - optreedt. Dit geeft de gebruiker de mogelijkheid om bij de start van een bepaald element bijvoorbeeld de naam van dit element af te drukken, maar natuurlijk ook om nog veel leukere dingen te doen, zoals ik in het voorbeeld in dit artikel zal laten zien.
Het opzetten van de parser
De SAX-parser kan met enkele eenvoudige opdrachten worden geïnitialiseerd. Allereerst moeten we een paar functies schrijven om de optredende events af te handelen.
PHP
- Code: Alles selecteren
function startElement( $parser, $elementname, $attributes )
PHP
- Code: Alles selecteren
function endElement( $parser, $elementname )
PHP
- Code: Alles selecteren
function characterData( $parser, $data )
Deze functie wordt gebruikt wanneer de parser
Vervolgens moeten wij de parser aanmaken met de functie
PHP
- Code: Alles selecteren
$parser = xml_parser_create();
Aan
- ISO-8859-1
- US-ASCII
- UTF-8
PHP
- Code: Alles selecteren
xml_parser_set_option( $parser, OPTION_NAME, OPTION_VALUE );
Bijvoorbeeld:
PHP
- Code: Alles selecteren
xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 );
In de PHP-documentatie wordt casefolding als volgt omschreven:
"The element handler functions may get their element names case-folded. Case-folding is defined by the XML standard as 'a process applied to a sequence of characters, in which those identified as non-uppercase are replaced by their uppercase equivalents'. In other words, when it comes to XML, case-folding simply means uppercasing."
In goed Nederlands: als de optie casefolding aan staat, worden alle elementnamen vervangen door hun equivalent in kapitalen; het element
Er zijn nog meer mogelijke instellingen, welke je op de website van PHP kunt vinden.
Nu we een parser hebben aangemaakt en de instellingen naar onze smaak hebben gewijzigd, zullen we aangeven welke functies de parser moet gebruiken tijdens het parsen. Dit gebeurt - onder andere - door middel van de volgende functies:
PHP
- Code: Alles selecteren
xml_set_element_handler( $parser, 'startElement', 'endElement' );
xml_set_character_data_handler( $parser, 'characterData' );
Waarin
Verder is het mogelijk om voor bijvoorbeeld processinginstructions ook handlers te selecteren (= functies specificeren). Kijk in de documentatie op de website van PHP welke handlers er allemaal mogelijk zijn.
Na het aangeven van de functies is het tijd voor het echte werk: we geven de parser de opdracht om daadwerkelijk te parsen, door middel van de volgende functie:
PHP
- Code: Alles selecteren
xml_parse( $parser, $text );
Hierin is
Na het parsen is het netjes om de parser op te ruimen, dit doen we door de functie
PHP
- Code: Alles selecteren
xml_parser_free( $parser );
Voorbeeld
In het volgende voorbeeld gaan we een receptenboekje in XML-formaat proberen te parsen met behulp van een PHP-script. In het script heb ik gebruik gemaakt van een klasse Recipe, die een recept beschrijft. Dit is echter niet noodzakelijk voor het inlezen van een document, maar ik vond het hier wel op zijn plaats.
Het PHP-script (recepten.php):
PHP
- Code: Alles selecteren
<?php
define( 'NONE', 'none' );
define( 'INGREDIENT', 'ingredient' );
define( 'STEP', 'step' );
define( 'NLN', "\n" );
define( 'TAB', "\t" );
/**
* Recept-klasse, bevat alle informatie over een recept.
*/
class Recipe
{
private $name;
private $quantity;
private $ingredients = array();
private $steps = array();
public function setName( $name )
{
$this->name = $name;
}
public function setQuantity( $quantity )
{
$this->quantity = $quantity;
}
public function addIngredient( $ingredient )
{
array_push( $this->ingredients, $ingredient );
}
public function addStep( $step )
{
array_push( $this->steps, $step );
}
public function parseRecipe()
{
$recipe = '<h1>'.$this->name.'</h1>'.NLN.
'<h2>Ingrediënten</h2>'.NLN.
'<ul>'.NLN;
foreach( $this->ingredients as $ingredient )
{
$recipe .= TAB.'<li>'.$ingredient.'</li>'.NLN;
}
$recipe .= '</ul>'.NLN.
'<h2>Bereiding</h2>'.NLN.
'<ol>'.NLN;
foreach( $this->steps as $step )
{
$recipe .= TAB.'<li>'.$step.'</li>'.NLN;
}
$recipe .= '</ol>'.NLN;
return $recipe;
}
}
$recipes = array();
$type = NONE;
$chars = '';
function startElement( $parser, $elementname, $attrs )
{
global $recipes, $type, $chars;
$size = sizeof( $recipes );
if( $elementname == 'recipe' )
{
$recipes[] = new Recipe();
$recipes[ $size ]->setName( $attrs[ 'name' ] );
$recipes[ $size ]->setQuantity( $attrs[ 'persons' ] );
}
elseif( $elementname == 'ingredient' )
{
$type = INGREDIENT;
$chars = '';
}
elseif( $elementname == 'step' )
{
$type = STEP;
$chars = '';
}
}
function endElement( $parser, $elementname )
{
global $recipes, $type, $chars;
$size = sizeof( $recipes ) - 1;
if( $elementname == STEP && $type == STEP )
{
$recipes[ $size ]->addStep( $chars );
}
elseif( $elementname == INGREDIENT && $type == INGREDIENT )
{
$recipes[ $size ]->addIngredient( $chars );
}
}
function characterData( $parser, $characters )
{
global $chars;
$chars .= $characters;
}
// Start parsing
$parser = xml_parser_create( 'ISO-8859-1' );
xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, 0 );
xml_set_element_handler( $parser, 'startElement', 'endElement' );
xml_set_character_data_handler( $parser, 'characterData' );
xml_parse( $parser, file_get_contents( 'recepten.xml' ) );
xml_parser_free( $parser );
foreach( $recipes as $recipe )
{
echo $recipe->parseRecipe();
}
?>
Het XML-bestand (recepten.xml):
XML
- Code: Alles selecteren
<?xml version="1.0" encoding="ISO-8859-1"?>
<recipes>
<recipe name="Omelet "Tante Pollewop"" persons="1">
<ingredient>1 Ei</ingredient>
<ingredient>Plakjes kaas</ingredient>
<step><![CDATA[Gooi het ei in een koekenpan.]]></step>
<step><![CDATA[Drapeer, wanneer het eiwit begint te stollen, wat plakjes kaas over de gehele omelet.]]></step>
<step><![CDATA[Wacht tot het eiwit gestold is en de kaas gesmolten.]]></step>
</recipe>
<recipe name="Ei" persons="1">
<ingredient>Kip</ingredient>
<step><![CDATA[Sla de kip op zijn kop met een hamer.]]></step>
<step><![CDATA[Vang het ei op zodra het uit de kip komt; eerder heeft namelijk geen zin.]]></step>
</recipe>
</recipes>
Event-based versus tree-based
Er zijn, strikt genomen, twee verschillende API's voor het parsen van XML: DOM (Document Object Model) en SAX.
DOM parst het document in een objectgeoriënteerde tree, zodat je een ouderelement heeft die een array met kindelementen bevat die op hun beurt misschien ook weer kinderelementen bevatten.
SAX parst het document op een event-based manier. Dit heeft als groot voordeel dat het mogelijk is een groot document, bijvoorbeeld een XML-bestand van 100 MegaByte, te parsen - zonder dat het gehele document in het geheugen hoeft te worden geplaatst.
In tegenstelling tot SAX biedt DOM wel de mogelijkheid om XML-bestanden niet alleen in te lezen, maar ook aan te maken.
Het is natuurlijk ook mogelijk om met behulp van een SAX-parser een objectgeoriënteerde tree aan te maken.
Nuttige links
- www.saxproject.org - De officiële website van het SAX-project.
- www.php.net/xml - De XML pagina van PHP.net.
- www.w3.org/xml - De pagina over XML van het W3C.
- RedRose
- Globale moderator
- Berichten: 1994
- Geregistreerd: 14 Jun 2005 18:12
1 bericht
• Pagina 1 van 1
Wie is er online?
Gebruikers in dit forum: Geen geregistreerde gebruikers en 1 gast