Forum und email

XML értelmező függvények

Bevezetés

Az XML (eXtensible Markup Language) olyan adatformátum, amit a Weben keresztüli adatcserére terveztek. Ezt az ajánlást a World Wide Web Consortium (W3C) dolgozta ki és gondozza. További információk az XML-ről és a kapcsolódó technológiákról a » https://www.w3.org/XML/ címen található.

Ez a kiterjesztés James Clark expat könyvtárát használja, amely a » https://www.jclark.com/xml/expat.html címen beszerezhető. Ez lehető teszi XML dokumentumok beolvasását, ún. elemzését, de nemazok érvényesítését. Három különböző PHP által is támogatott forrás-karakterkódolást támogat: US-ASCII, ISO-8859-1 és UTF-8. UTF-16 nincs támogatva.

Ez a kiterjesztés lehetőséget nyújt arra, hogy XML elemzőket hozzunk létre és azokhoz saját kezelőfüggvényeket rendeljünk hozzá, amelyek más és más események esetén futnak le. Minden XML elemzőnek néhány paramétere beállítható, ami a működését befolyásolja.

Követelmények

Ez a kiterjesztés az expat könyvtárat használja, amely a » https://www.jclark.com/xml/expat.html címen beszerezhető. A Makefile, amely ezzel a csomaggal jön alapértelmezés szerint nem telepíti a nekünk szükséges eljáráskönyvtárat, ehhez a következő sorokat kell beleírni:

libexpat.a: $(OBJS)
    ar -rc $@ $(OBJS)
    ranlib $@
Elérhető forrás RPM csomag is a következő helyen: » https://sourceforge.net/projects/expat/, ha nem akarsz kínlódni a fordítással ;)

Telepítés

Az Apache 1.3.7 vagy későbbi verziójával már együtt jár az expat könyvtár. Ekkor a PHP-t csak egyszerűen a --with-xml opcióval kell fordítani - minden kiegészítő elérési útvonal nélkül - és ekkor az Apacheüba épített expat könyvtárat használja majd.

Az UNIX rendszereken a configure parancsot kell a --with-xml kapcsolóval. Az expat könyvtárnak olyan helyen kell installálva lennie, ahol a fordító el tudja érni. Ha a PHP-t modulként Apache 1.3.9 (ennek vagy későbbi verziójú) alá installálod, akkor a PHP automatikusan az Apache beépített expat eljáráskönyvtárat fogja használni. Szükség lehet CPPFLAGS és a LDFLAGS környezeti változók beállítására a rendszeren, mielőtt elindítod a configure parancsot, ha az expat-ot valamilyen egzotikus helyre installálták.

A PHP telepítése.... Tada! Ezt kell(ene) látnod!

Futásidejű beállítások

Ez a kiterjesztés semmilyen konfigurációs beállításokat nem definiál a php.ini állományban.

Erőforrás típusok

Ez a kiterjesztés semmilyen erőforrás típust nem definiál.

Előre definiált állandók

Az itt listázott állandókat ez a kiterjesztés definiálja, és csak akkor elérhetőek, ha az adott kiterjesztés be van fordítva a PHP-be, vagy dinamikusan betöltött.

XML_ERROR_NONE (integer)
XML_ERROR_NO_MEMORY (integer)
XML_ERROR_SYNTAX (integer)
XML_ERROR_NO_ELEMENTS (integer)
XML_ERROR_INVALID_TOKEN (integer)
XML_ERROR_UNCLOSED_TOKEN (integer)
XML_ERROR_PARTIAL_CHAR (integer)
XML_ERROR_TAG_MISMATCH (integer)
XML_ERROR_DUPLICATE_ATTRIBUTE (integer)
XML_ERROR_JUNK_AFTER_DOC_ELEMENT (integer)
XML_ERROR_PARAM_ENTITY_REF (integer)
XML_ERROR_UNDEFINED_ENTITY (integer)
XML_ERROR_RECURSIVE_ENTITY_REF (integer)
XML_ERROR_ASYNC_ENTITY (integer)
XML_ERROR_BAD_CHAR_REF (integer)
XML_ERROR_BINARY_ENTITY_REF (integer)
XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF (integer)
XML_ERROR_MISPLACED_XML_PI (integer)
XML_ERROR_UNKNOWN_ENCODING (integer)
XML_ERROR_INCORRECT_ENCODING (integer)
XML_ERROR_UNCLOSED_CDATA_SECTION (integer)
XML_ERROR_EXTERNAL_ENTITY_HANDLING (integer)
XML_OPTION_CASE_FOLDING (integer)
XML_OPTION_TARGET_ENCODING (integer)
XML_OPTION_SKIP_TAGSTART (integer)
XML_OPTION_SKIP_WHITE (integer)

Eseménykezelők

A definiálható XML eseménykezelők:

A támogatott XML eseménykezelők:
PHP függvány ,amely regisztrálja a kezelőt esemény leírása
xml_set_element_handler() Elem esemény akkor történik, amikor az XML elemző egy elem kezdő vagy zárócímkéjével találkozik. A nyító és zárócímkékhez külön eseménykezelők rendelhetők.
xml_set_character_data_handler() (Elemzett) szöveges adatnak tekinthető durván minden, ami az XML dokumentumban nem a jelölésekhez tartozó tartalom, beleértve a jelölések közti térközöket is. Az XML elemző nem ad és nem vesz el semmilyen térkökaraktert az elemzés során a dokumentumból, ez teljes mértékben a feldolgozó alkalmazás feladata, illetve annak eldöntése, hogy ezek a karakterek értékes információt jelentenek vagy sem.
xml_set_processing_instruction_handler() PHP programozók számára ismerős lehet a feldolgozó utasítás (proccesing instructions: PI) fogalma. A <?php ?> maga is ilyen, ahol a php a feldolgozó utasítás "célpontja", magyarán a megcélzott feldolgozó. Ezek mind az alkalmazásfüggő elemek, kivéve az XML jelölésűeket, amely lefoglalt ebben az esetben is.
xml_set_default_handler() Azok az adatok, amelyek semmilyen más kezelő nem kezel le, ehhez a függvényhez kerülnek, pl.: XML és dokumentumtípus deklaráció.
xml_set_unparsed_entity_decl_handler() Ezt a kezelőt hívja meg az elemző, ha jelölés deklarációs egyedet (unparsed, NDATA entity). kell feldolgozni.
xml_set_notation_decl_handler() Ez a kezelő felelős a jelölések deklarációjáért.
xml_set_external_entity_ref_handler() Ezt az kezelőt hívja meg az elemző, ha egy külső egyedhivatkozást talál. Ez lehet állományra vagy URL-re történő hivatkozás. Lásd a Példák külső egyedek kezelésére c. fejezetet!

Betű egységesítés (case-folding)

Az elemek nevei kisbetűket és nagybetűket vegyesen tartalmazhatnak. Az elemkezelő fügvények szempontjából ez nem mindegy, ezért az XML szabvány definiált egy betűkezelő szabályt, mely szerint "ha kisbetűt, nagybetűt vegyesen tartalmazó karaktersorozatot kell feldolgozni, akkor a karaktersorozatban a kisbetűket ki kell cserélni a nekik megfelelő nagybetűkre". Más szavakkal, amikor egy karaktersorozat érkezik az XML értelmezőhöz, a betűkezelés egyszerűen a teljes nagybetűre váltást jelenti.

Alapértelmezés szerint az XML kezelők már nagybetűre váltott formában kapják meg a neveket az értelmezőtől. Ez a viselkedés azonban lekérdezhető ill. megváltoztatható az XML elemző következő két függvényével: xml_parser_get_option() (lekérdezés) és a xml_parser_set_option() (beállítás) függvényekkel.

Hibaüzenetek

A következő hibaüzeneteket definálták (az xml_parse() függvény visszatérési értékei lehetnek):

  • 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

Karakterkódolások

A PHP XML kiterjesztése támogatja az » Unicode karakterkészeletet különböző karakterkódolások által. Kétféle karakterkódolás különböztetünk meg, az ún. forrás kódolást és a cél kódolást. A PHP belső, értelmezési célokra a dokumentumokat mindig UTF-8 karakterkódolás szerint kódolja.

A forrás-kódolás az XML dokumentum értelmezése, elemzése során használja. Az XML értelmezőt létrehozásakor meg lehet határozni az elemző forrás kódolását, amit később már nem lehet megváltoztatni. A támogatott karakterkészletek a forrás kódolás számára a következők: ISO-8859-1, US-ASCII és az UTF-8. Az első kettő egybájtos kódolás, ami annyit tesz, hogy minden karaktert egyetlen bájton ábrázolnak. Az UTF-8 egy és négy bájt között különböző hosszúságú bitláncon (21 hosszúig) tudja ábrázolja a karaktereket. A forrás kódolás alapértelmezett karakterkészlete a PHP-ben a ISO-8859-1.

A cél-kódolás akkor készül el, amikor a PHP átadja az adatokat az XML kezelő függvényeknek. Amikor egy XML elemző létrejön, a cél-kódolás a forrás-kódolásához igazodik, de ezt meg lehet változtatni a későbbiek során. A cél-kódolás hatással lesz a karakteres adatra, XML elemek címkéire és a feldolgozó utasításokban definiált célpontokra is!

Ha az XML elemző olyan karaktert talál, mely nincs definiálva a forrás-kódolás karakterkészletében, akkor ez hibát okoz.

Ha az értelmezett XML dokumentumban találkozik a PHP egy olyan karakterrel, amit nem nem tud megjeleníteni a cél-kódolás karakterkészlete, akkor a problémás karaktert "lefokozza". Ez annyit jelent, hogy kérdőjelet rak a helyébe.

Példák

Here are some example PHP scripts parsing XML documents.

XML Element Structure Example

This first example displays the stucture of the start elements in a document with indentation.

Example#1 Show XML Element Structure

<?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($fp4096)) {
    if (!
xml_parse($xml_parser$datafeof($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);

XML Tag Mapping Example

Example#2 Map XML to HTML

This example maps tags in an XML document directly to HTML tags. Elements not found in the "map array" are ignored. Of course, this example will only work with a specific XML document type.

$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);

XML External Entity Example

This example highlights XML code. It illustrates how to use an external entity reference handler to include and parse other documents, as well as how PIs can be processed, and a way of determining "trust" for PIs containing code.

XML documents that can be used for this example are found below the example (xmltest.xml and xmltest2.xml.)

Example#3 External Entity Example

$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 "&lt;<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 "&gt;";
}

function endElement($parser, $name) {
    print "&lt;/<font color=\"#0000cc\">$name</font>&gt;";
}

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("Untrusted PHP code: <i>%s</i>",
                        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);

?>

Example#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;
 <section xml:id="about">
  <title>About this Document</title>
  <para>
   <!-- this is a comment -->
   <?php print 'Hi!  This is PHP version '.phpversion(); ?>
  </para>
 </section>
</chapter>

This file is included from xmltest.xml:

Example#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>

Table of Contents