|
|
CV. Analyseur syntaxique XML
Le langage XML (eXtensible Markup Language (Langage � Balises
Etendu)) est un format structur� de donn�es pour les
�changes sur le web. C'est un standard d�fini par le
consortium World Wide Web (W3C). Plus d'informations � propos
du XML et des technologies aff�rentes sont accessibles (en anglais)
.
Cette extension de PHP utilise expat,
disponible � .
Le fichier Makefile livr� avec expat
ne construit pas par d�faut de librairie : il faut utiliser
la ligne suivante :
libexpat.a: $(OBJS)
ar -rc $@ $(OBJS)
ranlib $@ |
Les sources RPM de expat sont disponibles �
.
Notez que si vous utilisez Apache-1.3.7 ou plus r�cent,
vous disposez d�j� de la librairie expat.
Configurez simplement PHP avec
--with-xml
(sans aucun autre information) et la librairie expat d'Apache sera
automatiquement utilis�e.
Sous UNIX, lancez la configuration de PHP avec l'option
--with-xml,
la librairie expat �tant install�e
l� o� votre compilateur peut la trouver.
Si vous compilez PHP comme module de PHP 1.3.9 ou plus r�cent,
PHP utilisera automatiquement le module expat
livr� avec Apache. Il vous faudra peut �tre fixer
les valeurs des variables d'environnement CPPFLAGS
et LDFLAGS, si vous avez fait une installation exotique.
Compilez PHP. Tada! C'est fait !
Cette extension PHP supporte la librairie expat
de James Clark sous PHP. Cela vous permettra d'analyser mais
pas de valider les documents XML. Il supporte trois types de
codage diff�rents, disponibles aussi sous PHP:
US-ASCII, ISO-8859-1 et
UTF-8. UTF-16 n'est pas support�.
Cette extension vous permet de cr�er des
analyseurs XML
puis de d�finir des points d'entr�e
pour chaque �v�nement XML. Les analyseurs XML disposent
de quelques
param�trages.
Les gestionnaires d'�v�nements XML sont:
Tableau 1. Les gestionnaires d'�v�nements XML Fonction PHP de configuration du gestionnaire | Description de l'�v�nement |
---|
xml_set_element_handler() |
Un �v�nement est g�n�r�
� chaque fois que l'analyseur XML rencontre une balise de
d�but ou de fin. Deux gestionnaires sont disponibles : un
pour le d�but, et un pour la fin.
|
xml_set_character_data_handler()
|
"Character data" correspond grosso modo � tout ce qui n'est
pas une balise XML, y compris les espaces entre les balises. Notez
bien que l'analyseur XML n'ajoute ou n'efface aucun espace, et que
c'est � l'application (c'est-�-dire vous) de
d�cider de la signification de ces espaces.
|
xml_set_processing_instruction_handler()
|
Les programmeurs PHP sont habitu�s aux instructions
ex�cutables (processing instructions ou PIs).
<?php ?> est une instruction ex�cutable o�
php est appel� programme cible. Ces instructions sont
g�r�es de mani�re sp�cifiques,
(sauf le programme cible, qui est r�serv� � XML).
| xml_set_default_handler() |
Tout ce qui n'a pas trouv� de gestionnaire est transmis
au gestionnaire par d�faut. Vous retrouverez par exemple,
les d�clarations de type de document dans ce gestionnaire.
|
xml_set_unparsed_entity_decl_handler()
|
Ce gestionnaire est appel� pour g�rer les
d�claration des entit�s non analys�s.
|
xml_set_notation_decl_handler()
|
Ce gestionnaire est appel� pour g�rer les notations.
|
xml_set_external_entity_ref_handler()
|
Ce gestionnaire est appel� lorsque l'analyseur XML trouve une
r�f�rence � un fichier externe. Cela peut
�tre un fichier, ou une URL. Reportez-vous �
entit� externe
pour un exemple.
|
Les fonctions de gestion des balises peuvent rencontrer des balises en
minuscule, majuscule ou encore dans un m�lange des deux. En XML,
la proc�dure standard est d' "identifier les s�quences de
caract�re qui ne sont pas reconnues comme majuscule, et de les
remplacer par leur �quivalent majuscule". En d'autres termes,
XML met toutes lettres en majuscules.
Par d�faut, tous les noms des �l�ments qui sont
transmis aux fonctions de gestion sont mises en majuscule. Ce
comportement est contr�l� par l'analyseur XML, et
peut �tre lu et modifi� avec les fonctions respectives
xml_parser_get_option() et
xml_parser_set_option(), respectivement.
Les constantes suivantes sont d�finies comme des codes
d'erreurs XML : (retourn�e par xml_parse())
XML_ERROR_NONE | XML_ERROR_NO_MEMORY | XML_ERROR_SYNTAX | XML_ERROR_NO_ELEMENTS | XML_ERROR_INVALID_TOKEN | XML_ERROR_UNCLOSED_TOKEN | XML_ERROR_PARTIAL_CHAR | XML_ERROR_TAG_MISMATCH | XML_ERROR_DUPLICATE_ATTRIBUTE | XML_ERROR_JUNK_AFTER_DOC_ELEMENT | XML_ERROR_PARAM_ENTITY_REF | XML_ERROR_UNDEFINED_ENTITY | XML_ERROR_RECURSIVE_ENTITY_REF | XML_ERROR_ASYNC_ENTITY | XML_ERROR_BAD_CHAR_REF | XML_ERROR_BINARY_ENTITY_REF | XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF | XML_ERROR_MISPLACED_XML_PI | XML_ERROR_UNKNOWN_ENCODING | XML_ERROR_INCORRECT_ENCODING | XML_ERROR_UNCLOSED_CDATA_SECTION | XML_ERROR_EXTERNAL_ENTITY_HANDLING |
L'extension XML de PHP supporte les caract�res
gr�ce �
diff�rents codages. Il y a deux types de codages de
caract�res : le codage � la source et le codage �
la cible. PHP utilise le UTF-8 comme
repr�sentation interne.
L'encodage � la source est effectu� lors de
l'analyse du fichier par XML.
Lors de la cr�ation
d'un analyseur XML), un type de codage � la
source doit �tre sp�cifi� (et il ne pourra plus
�tre modifi� jusqu'� la destruction de
l'analyseur). Les codages support�s sont :
ISO-8859-1, US-ASCII et
UTF-8. Les deux derniers sont des codages
� un seul octet, c'est-�-dire que les caract�res
sont repr�sent�s sur un seul octet. UTF-8
peut repr�senter des caract�res compos�s par un
nombre variable de bits (jusqu'� 21), allant de 1 �
quatre octets. Le codage par d�faut utilis� par PHP
ISO-8859-1.
Le codage � la cible est effectu� lorsque PHP transfert
les donn�es aux gestionnaires XML. Lorsqu'un analyseur est
cr��, le codage � la cible est sp�cifi�
de la m�me fa�on que le codage � la source, mais
il peut �tre modifi� � tout moment. Le codage
� la cible affectera les balises, tout comme les
donn�es brutes, et les noms des instructions ex�cutables.
Si l'analyseur XML rencontre un caract�re qu'il ne
conna�t pas (hors limite, par exemple), il retournera une erreur.
Si PHP rencontre un caract�re dans le document XML analys�,
qu'il ne peut pas repr�senter dans le codage � la cible
choisi, le caract�re sera remplac� par un point
d'interrogation (cette attitude est susceptible de changer
ult�rieurement).
Voici une liste d'exemple de code PHP qui analyse un document XML.
Ce premier exemple affiche la structure de l'�l�ment
de d�but dans un document avec indentation.
Exemple 1. Afficher une structure XML <?php
$file = "data.xml";
$depth = array();
function startElement($parser, $name, $attrs) {
global $depth;
for ($i = 0; $i < $depth[$parser]; $i++) {
print " ";
}
print "$name\n";
$depth[$parser]++;
}
function endElement($parser, $name) {
global $depth;
$depth[$parser]--;
}
$xml_parser = xml_parser_create();
xml_set_element_handler($xml_parser, "startElement", "endElement");
if (!($fp = fopen($file, "r"))) {
die("could not open XML input");
}
while ($data = fread($fp, 4096)) {
if (!xml_parse($xml_parser, $data, feof($fp))) {
die(sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
xml_parser_free($xml_parser);
?> |
|
Exemple 2. XML Transtypage XML -> HTML
Cet exemple remplace les balises XML d'un document par des balises
HTML. Les �l�ments inconnus seront ignor�s.
Bien entendu, cet exemple sera appliqu� � un type
pr�cis de fichiers XML.
<?php
$file = "data.xml";
$map_array = array(
"BOLD" => "B",
"EMPHASIS" => "I",
"LITERAL" => "TT"
);
function startElement($parser, $name, $attrs) {
global $map_array;
if ($htmltag = $map_array[$name]) {
print "<$htmltag>";
}
}
function endElement($parser, $name) {
global $map_array;
if ($htmltag = $map_array[$name]) {
print "</$htmltag>";
}
}
function characterData($parser, $data) {
print $data;
}
$xml_parser = xml_parser_create();
// use case-folding so we are sure to find the tag in $map_array
xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, TRUE);
xml_set_element_handler($xml_parser, "startElement", "endElement");
xml_set_character_data_handler($xml_parser, "characterData");
if (!($fp = fopen($file, "r"))) {
die("could not open XML input");
}
while ($data = fread($fp, 4096)) {
if (!xml_parse($xml_parser, $data, feof($fp))) {
die(sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
xml_parser_free($xml_parser);
?> |
|
Cet exemple exploite les r�f�rences externes de XML :
il est possible d'utiliser un gestionnaire d'entit� externe
pour inclure et analyser les documents, tous comme les instructions
ex�cutables peuvent servir � inclure et analyser
d'autres documents, et aussi fournir une indication de confiance
(voir plus bas).
Le document XML qui est utilis� dans cet exemple est fourni plus
loin dans l'exemple (xmltest.xml et
xmltest2.xml).
Exemple 3. Entit� externe <?php
$file = "xmltest.xml";
function trustedFile($file) {
// only trust local files owned by ourselves
if (!eregi("^([a-z]+)://", $file)
&& fileowner($file) == getmyuid()) {
return TRUE;
}
return FALSE;
}
function startElement($parser, $name, $attribs) {
print "<<font color=\"#0000cc\">$name</font>";
if (sizeof($attribs)) {
while (list($k, $v) = each($attribs)) {
print " <font color=\"#009900\">$k</font>=\"<font
color=\"#990000\">$v</font>\"";
}
}
print ">";
}
function endElement($parser, $name) {
print "</<font color=\"#0000cc\">$name</font>>";
}
function characterData($parser, $data) {
print "<B>$data</B>";
}
function PIHandler($parser, $target, $data) {
switch (strtolower($target)) {
case "php":
global $parser_file;
// If the parsed document is "trusted", we say it is safe
// to execute PHP code inside it. If not, display the code
// instead.
if (trustedFile($parser_file[$parser])) {
eval($data);
} else {
printf("Code PHP peu s�r : <B>%s</B>",
htmlspecialchars($data));
}
break;
}
}
function defaultHandler($parser, $data) {
if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
printf('<font color="#aa00aa">%s</font>',
htmlspecialchars($data));
} else {
printf('<font size="-1">%s</font>',
htmlspecialchars($data));
}
}
function externalEntityRefHandler($parser, $openEntityNames, $base, $systemId,
$publicId) {
if ($systemId) {
if (!list($parser, $fp) = new_xml_parser($systemId)) {
printf("Could not open entity %s at %s\n", $openEntityNames,
$systemId);
return FALSE;
}
while ($data = fread($fp, 4096)) {
if (!xml_parse($parser, $data, feof($fp))) {
printf("XML error: %s at line %d while parsing entity %s\n",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser), $openEntityNames);
xml_parser_free($parser);
return FALSE;
}
}
xml_parser_free($parser);
return TRUE;
}
return FALSE;
}
function new_xml_parser($file) {
global $parser_file;
$xml_parser = xml_parser_create();
xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 1);
xml_set_element_handler($xml_parser, "startElement", "endElement");
xml_set_character_data_handler($xml_parser, "characterData");
xml_set_processing_instruction_handler($xml_parser, "PIHandler");
xml_set_default_handler($xml_parser, "defaultHandler");
xml_set_external_entity_ref_handler($xml_parser, "externalEntityRefHandler");
if (!($fp = @fopen($file, "r"))) {
return FALSE;
}
if (!is_array($parser_file)) {
settype($parser_file, "array");
}
$parser_file[$xml_parser] = $file;
return array($xml_parser, $fp);
}
if (!(list($xml_parser, $fp) = new_xml_parser($file))) {
die("could not open XML input");
}
print "<pre>";
while ($data = fread($fp, 4096)) {
if (!xml_parse($xml_parser, $data, feof($fp))) {
die(sprintf("XML error: %s at line %d\n",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
print "</pre>";
print "parse complete\n";
xml_parser_free($xml_parser);
?> |
|
Exemple 4. xmltest.xml <?xml version='1.0'?>
<!DOCTYPE chapter SYSTEM "/just/a/test.dtd" [
<!ENTITY plainEntity "FOO entity">
<!ENTITY systemEntity SYSTEM "xmltest2.xml">
]>
<chapter>
<TITLE>Title &plainEntity;</TITLE>
<para>
<informaltable>
<tgroup cols="3">
<tbody>
<row><entry>a1</entry><entry morerows="1">b1</entry><entry>c1</entry></row>
<row><entry>a2</entry><entry>c2</entry></row>
<row><entry>a3</entry><entry>b3</entry><entry>c3</entry></row>
</tbody>
</tgroup>
</informaltable>
</para>
&systemEntity;
<sect1 id="about">
<title>About this Document</title>
<para>
<!-- this is a comment -->
<?php print 'Hi! This is PHP version '.phpversion(); ?>
</para>
</sect1>
</chapter> |
|
Ce fichier est inclus depuis xmltest.xml:
Exemple 5. xmltest2.xml <?xml version="1.0" ?>
<!DOCTYPE foo [
<!ENTITY testEnt "test entity">
?>
<foo>
<element attrib="value"?>
&testEnt;
<?php print "This is some more PHP code being executed."; ?>
</foo> |
|
User Contributed Notes Analyseur syntaxique XML |
|
[email protected]
12-Jan-1999 10:05 |
|
In the installation section, be sure that the indents in the code you add
to the Makefile are tabs, not spaces. make will choke
otherwise.
Additionally, you need to copy two header files into
your /usr/local/include or
equivalent:
$EXPAT_SRC/xmltok/xmltok.h
$EXPAT_SRC/xmlparse/xmlparse.h
|
|
[email protected]
07-Jul-1999 04:21 |
|
When using the XML parser, make sure you're not using the magic quotes
option (e.g. use set_magic_quotes_runtime(0) if it's not the compiled
default), otherwise you'll get 'not well-formed' errors when dealing with
tags with attributes set in them.
|
|
[email protected]
16-Aug-1999 10:13 |
|
"The expat library should be installed somewhere your compiler can
find it." is a little vague. Here is a quick install guide:
1)
download expat.zip
2) mv expat.zip /dir/of/expat
3) unzip
expat.zip
4) cd expat
5) Add these lines to Makefile:
libexpat.a: $(OBJS)
(tab) ar -rc $@ $(OBJS)
(tab)
ran lib $@
6) make
7) cp libexpat.a /usr/local/lib
8) mkdir
/usr/local/include/xml
9) cd xmlparse
10) cp *.h
/usr/local/include/xml
11) cd ../xmltok
12) cp *.h
/usr/local/include/xml
13) cd ../xmlwf
14) cp *.h
/usr/local/include/xml
Then reconfigure and make php, then apache.
|
|
[email protected]
30-Oct-1999 04:40 |
|
I'm not sure if anyone else has had or will have this problem, but here is
my solution. For some reason, the PHP compile did recognise the Apache
1.3.9 support for XML. I circumvented this by creating a link from
/usr/local/include/xml to the Apache src/lib/expat-lite directory. I then
however ran into problems with the Apache compile. It was looking for
libexpat.a which hadn't been created. I tried to create this by
downloading the source and modifying the Makefile, but it wasnt created
for some reason. Finally, I resorted to creating the libexpat.a file by
hand:
ar -rc xmltok/xmltok.o
ar -q xmltok/xmlrole.o
ar
-q xmlwf/xmlwf.o
ar -q xmlwf/xmlfile.o
ar -q
xmlwf/codepage.o
ar -q xmlparse/xmlparse.o
ar -q
xmlparse/hashtable.o
I hope this helps someone, because it would
have saved me a lot of time. Also note that I was getting an ANSI
non-compliance error in the Apache build process. After added the -v
swicth to line 2141 as pointed out in the FAQ, I found out it was the
missing libexpat.a package.
|
|
[email protected]
15-Dec-1999 03:25 |
|
Remember, that when adding the lines for making:
libexpat.a:
$(OBJS)
<tab> ar -rc $@ $(OBJS)
<tab> ranlib
$@
,you'll have to do a "make libexpat.a" after running
"make".
|
|
[email protected]
17-Feb-2000 05:31 |
|
The link
is no active. For the expat.zip do a FTP file search.
|
|
[email protected]
28-Sep-2000 01:39 |
|
I've discovered some unusual behaviour in this API when ampersand entities
are parsed in cdata; for some reason the parser breaks up the section
around the entities, and calls the handler repeated times for each of the
sections. If you don't allow for this oddity and you are trying to put the
cdata into a variable, only the last part will be stored.
You
can get around this with a line like:
$foo .= $cdata;
If
the handler is called several times from the same tag, it will append
them, rather than rewriting the variable each time. If the entire cdata
section is returned, it doesn't matter.
May happen for other
entities, but I haven't investigated.
Took me a while to figure
out what was happening; hope this saves someone else the trouble.
|
|
[email protected]
06-Oct-2000 07:37 |
|
There's a really good article on XML parsing with PHP at
|
|
[email protected]
31-Mar-2001 12:35 |
|
Excellent IMHO XPath library for XML manipulation. Doesn't requires the
XML libraries to be installed. Take a look:
|
|
[email protected]
24-Jan-2002 02:43 |
|
I had to TRIM the data when I passed one large String containig a
wellformed XML-File to xml_parse. The String was read by CURL, which
aparently put a BLANK at the end of the String. This BLANK produced a
"XML not wellformed"-Error in xml_parse!
|
|
jason@NOSPAM_projectexpanse_NOSPAM.com
26-Feb-2002 10:11 |
|
For newbies wanting a good tutorial on how to actually get started and
where to go from this listing of functions, then visit:
It
shows an excellent example of how to read the XML data into a class file
so you can actually process it, not just display it all pretty-like, like
many tutorials on PHP/XML seem to be doing.
|
|
[email protected]
22-Mar-2002 07:16 |
|
In reference to the note made by [email protected] about parsing
entities:
I could be wrong, but since it is possible to define your
own entities within an XML DTD, the cdata handler function parses these
individually to allow for your own implementation of those entities within
your cdata handler.
|
|
[email protected]
15-Apr-2002 08:23 |
|
I put up a good, simple, real world example of how to parse XML documents.
While the sample grabs stock quotes off of the web, you can tweak it to do
whatever you need.
|
|
[email protected]
14-Aug-2002 07:59 |
|
[Editor's note: see also xml_parse_into_struct().]
Very simple
routine to convert an XML file into a PHP structure. $obj->xml contains
the resulting PHP structure. I would be interested if someone could
suggest a cleaner method than the evals I am
using.
<?
$filename = 'sample.xml';
$obj->tree =
'$obj->xml';
$obj->xml = '';
function
startElement($parser, $name, $attrs) {
global $obj;
// If var already defined, make array
eval('$test=isset('.$obj->tree.'->'.$name.');');
if ($test)
{
eval('$tmp='.$obj->tree.'->'.$name.';');
eval('$arr=is_array('.$obj->tree.'->'.$name.');');
if
(!$arr) {
eval('unset('.$obj->tree.'->'.$name.');');
eval($obj->tree.'->'.$name.'[0]=$tmp;');
$cnt = 1;
}
else {
eval('$cnt=count('.$obj->tree.'->'.$name.');');
}
$obj->tree .= '->'.$name."[$cnt]";
}
else {
$obj->tree .= '->'.$name;
}
if (count($attrs)) {
eval($obj->tree.'->attr=$attrs;');
}
}
function endElement($parser, $name) {
global
$obj;
// Strip off last ->
for($a=strlen($obj->tree);$a>0;$a--) {
if
(substr($obj->tree, $a, 2) == '->') {
$obj->tree =
substr($obj->tree, 0, $a);
break;
}
}
}
function characterData($parser, $data) {
global
$obj;
eval($obj->tree.'->data=\''.$data.'\';');
}
$xml_parser
= xml_parser_create();
xml_set_element_handler($xml_parser,
"startElement",
"endElement");
xml_set_character_data_handler($xml_parser,
"characterData");
if (!($fp = fopen($filename,
"r"))) {
die("could not open XML
input");
}
while ($data = fread($fp, 4096)) {
if
(!xml_parse($xml_parser, $data, feof($fp))) {
die(sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)));
}
}
xml_parser_free($xml_parser);
print_r($obj->xml);
return
0;
?>
|
|
|
| |