CLXVI. XML parser συναρτήσεις

Εισαγωγή

Η XML (eXtensible Markup Language) είναι μια μορφή δεδομένων για ανταλλαγή δομημένων αρχείων στο Web. Είναι ένα standard καθορισμένο από το The World Wide Web consortium (W3C). Πληροφορίες σχετικά με την XML και τις συσχετιζόμενες μ'αυτήν τεχνολογίες μπορείτε να βρείτε στο http://www.w3.org/XML/.

Αυτή η επέκταση της PHP υλοποιεί υποστήριξη για την expat του James Clark στην PHP. Αυτό το εργαλείο σας επιτρέπεται να μεταγλωτίσετε, αλλά όχι να ελένξετε την εγκυρότητα, των XML αρχείων. Υποστηρίζει τρία πηγές κωδικοποίησης χαρακτήρων που παρέχονται επίσης και από την by PHP: την US-ASCII, την ISO-8859-1 και την UTF-8. Η UTF-16 δεν υποστηρίζεται.

Αυτή η επέκταση σας επιτρέπει να δημιουργήσετε XML parsers και στη συνέχεια να ορίσετε handlers για διαφορετικά XML events. Ο κάθε XML parser έχει επίσης και μερικές παραμέτρους τις οποίες μπορείτε να ρυθμίσετε.

Απαιτήσεις

Αυτή η επέκταση χρησιμοποιεί την expat, η οποία μπορεί να βρεθεί στο http://www.jclark.com/xml/expat.html. Η Makefile που συνοδεύει την expat δεν δημιουργεί μια library εκ των πραγμάτων, μπορείτε να χρησιμοποιήσετε αυτό για να δημιουργήσετε έναν κανόνα για εκείνο:
libexpat.a: $(OBJS)
    ar -rc $@ $(OBJS)
    ranlib $@
Το source RPM πακέτο της expat μπορείτε να το βρείτε στο http://sourceforge.net/projects/expat/.

Εγκατάσταση

Αυτές οι συναρτήσεις είναι ενεργοποιημένες by default, χρησιμοποιώντας την bundled expat library. Μπορείτε να απενεργοποιήσετε την υποστήριξη της XML με την --disable-xml. Αν κάνετε compile την PHP ως module για τον Apache 1.3.9 και μετά, η PHP θα χρησιμοποιήσει αυτόματα την bundled expat library από τον Apache. Σε περίπτωση που δε θέλετε να χρησιμοποιήσετε την bundled expat library ρυθμίστε την PHP --with-expat-dir=DIR, όπου η DIR θα πρέπει να δείχνει στο βασικό κατάλογο εγκατάστασης του expat.

Η έκδοση για windows της PHP έχει ενσωματωμένη υποστήριξη για αυτή την επέκταση. Δεν χρειάζεται να φορτώσετε κάποια πρόσθετη επέκταση για να χρησιμοποιήσετε αυτές τις συναρτήσεις.

Ρυθμίσεις κατά την εκτέλεση

Αυτή η επέκταση δεν έχει directives ρύθμισης ορισμένα στο php.ini.

Τύποι Πόρων

xml

Η xml resource όπως επιστρέφεται από την xml_parser_create() και την xml_parser_create_ns() κάνει αναφορά σε ένα στιγμιότυπο του xml parser για να χρησιμοποιηθεί με τις συναρτήσεις που παρέχονται από αυτή την επέκταση.

Προκαθορισμένες Σταθερές

Οι σταθερές παρακάτω ορίζονται από αυτή την επέκταση, και θα είναι διαθέσιμες μόνο αν η επέκταση έχει γίνει compile μέσα στην PHP ή έχει φορτωθεί δυναμικά κατά την εκτέλεση.

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)

Event Handlers

Οι event handlers (χειριστές γεγονότων) της XML που έχουν οριστεί είναι:

Ðßíáêáò 1. XML handlers που υποστηρίζονται

Συνάρτηση της PHP που ορίζει τον handlerΠεριγραφή Event
xml_set_element_handler() Τα events ενός στοιχείου ενεργοποιούνται όταν ο XML parser συναντά tags αρχής ή τέλους. Υπάρχουν ξεχωριστοί handlers για tags αρχής και tags τέλους.
xml_set_character_data_handler() Τα δεδομένα χαρακτήρων είναι σχεδόν όλα τα περιεχόμενα των XML αρχείων που δεν είναι markup, συμπεριλαμβανομένου των κενών ανάμεσα στα tags. Σημειώστε ότι ο XML parser δεν προσθέτει ή αφαιρεί κάποιο κενό, εξαρτάται από την εφαρμογή σας (από εσάς) να αποφασισθεί αν τα κενά είναι σημαντικά.
xml_set_processing_instruction_handler() Οι προγραμματιστές σε PHP έχουν οικειότητα με εντολές διαδικασιών (processing instructions - PIs). Η <?php ?> είναι μια processing instruction, όπου η php καλείται "PI target". Ο χειρισμός αυτών καθορίζεται από τις εφαρμογές, εκτός από το οτι όλοι οι PI targets που αρχίζουν με "XML" είναι δεσμευμένοι.
xml_set_default_handler() Ό,τι δεν πάει σε κάποιο άλλο handler πηγαίνει στον προκαθορισμένο handler. Θα πάρετε πράγματα όπως η XML και η δήλωση τύπων του αρχείου στο προκαθορισμένο handler.
xml_set_unparsed_entity_decl_handler() Αυτός ο handler θα καλείται για δήλωση μια οντότητας (NDATA) στην οποία δεν έχει γίνει parse.
xml_set_notation_decl_handler() Αυτός ο handler καλείται για δήλωση μια σημείωσης (notation).
xml_set_external_entity_ref_handler() Αυτός ο handler καλείται όταν ο XML parser βρίσκει μια αναφορά σε μια εξωτερικά μεταγλωττισμένη γενική οντότητα. Αυτό μπορεί να είναι ναναφορά σε ένα αρχείο ή σε ένα URL, για παράδειγμα. Δείτε το παράδειγμα για εξωτερικές οντότητες για μια επίδειξη.

Case Folding

Οι συναρτήσεις που χειρίζονται ένα στοιχείο μπορούν να πάρουν τα element ονόματα τους ως case-folded. Το Case-folding ορίζεται από το standard της XML ως "η διαδικασία που εφαρμόζεται σε μια ακολουθία χαρακτήρων, στην οποία αυτοί οι identified ως μη-κεφαλαίοι αντικαθίστανται από τους αντίστοιχους τους κεφαλαίους". Με άλλα λόγια, όταν ερχόμαστε στην XML, το case-folding σημαίνει απλά μετατροπή σε κεφαλαία.

Είναι προκαθορισμένο ότι όλα τα ονόματα των στοιχείων που περνούν σε συναρτήσεις handler είναι case-folded. Αυτή η συμπεριφορά μπορεί να ερωτηθεί και να ελενχθεί ανά XML parser με τις συναρτήσεις xml_parser_get_option() και xml_parser_set_option() , αντίστοιχα.

Κωδικοί Λάθους (Error Codes)

Οι ακόλουθες σταθερές έχουν οριστεί για κωδικούς λάθους της XML (όπως επιστρέφονται από την 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

Κωδικοποίηση Χαρακτήρων

Η επέκταση σε XML της PHP υποστηρίζει το σύνολο χαρακτήρων Unicode διαμέσου διαφορετικών κωδικοποιήσεων χαρακτήρων. Υπάρχουν δύο τύποι κωδικοποίησης χαρακτήρων, η source κωδικοποίηση και η target κωδικοποίηση. η εσωτερική αναπαράσταση της PHP ενός αρχείου είναι πάντα κωδικοποιημένη με UTF-8.

Η Source κωδικοποίηση γίνεται όταν ένα XML αρχείο μεταγλωττίζεται. Όταν δημιουργείται ένας XML parser, η source κωδικοποίηση μπορεί να προσδιοριστεί (αυτή η κωδικοποίηση δεν μπορεί να αλλάξει αργότερα στο χρόνο ζωής του XML parser). Οι source κωδικοποιήσεις που υποστηρίζονται είναι η ISO-8859-1, η US-ASCII και η UTF-8. Οι δυο πρώτες είναι single-byte κωδικοποιήσεις, το οποίο σημαίνει ότι κάθε χαρακτήρας αναπαρίσταται από ένα μόνο byte. Η UTF-8 μπορεί να κωδικοποιήσει χαρακτήρες που αποτελούνται από έναν μεταβλητό αριθμό από bits (μέχρι 21) από ένα μέχρι τέσσετα bytes. Η προκαθορισμένη source κωδικοποίηση που χρησιμοποιείται στην PHP είναι η ISO-8859-1.

Η Target κωδικοποίηση γίνεται όταν η PHP μεταφέρει δεδομένα σε XML handler συναρτήσεις. Όταν ένας XML parser δημιουργείται, η target κωδικοποίηση ορίζεται ίδια με την source κωδικοποίηση, αλλά αυτό μπορεί να αλλάξει σε οποιοδήποτε σημείο. Η target κωδικοποίηση θα επηρεάσει τα δεδομένα των χαρακτήρων καθώς επίσης και τα ονόματα των tags και τα processing instruction targets.

Αν ο XML parser συναντήσει χαρακτήρες εκτός πεδίου που η source κωδικοποίηση μπορεί να αναπαραστήσει, θα επιστρέψει ένα λάθος.

Αν η PHP συνατήσει χαρακτήρες στο μεταγλωττισμένο XML αρχείο που δεν μπορεί να αναπαραστήσει στην επιλεγμένη target κωδικοποίηση, οι προβληματικοί χαρακτήρες θα "υποβιβαστούν". Προσ το παρόν, αυτό σημαίνει ότι τέτοιοι χαρακτήρες αντικαθίστανται από το αγγλικό ερωτηματικό.

Παραδείγματα

Εδώ υπάρχουν μερικά ενδεικτικά PHP scripts που κάνουν μεταγλώττιση σε XML αρχεία.

Παράδειγμα δομής στοιχείου (element) XML

Το πρώτο παράδειγμα εμφανίζει τη δομή των αρχικών elements σε ένα αρχείο με εσοχές.

ÐáñÜäåéãìá 1. Εμφάνιση της δομής ενός XML Element

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

Παράδειγμα για αντιστοίχιση των XML Tags

ÐáñÜäåéãìá 2. Αντιστοιχία XML σε HTML

Αυτό το παράδειγμα αντιστοιχεί τα tags σε ένα XML αρχείο κατευθείαν σε HTML tags. Τα Elements που δεν υπάρχουν στον "map array" αγνοούνται. Φυσικά, αυτό το παράδειγμα θα δουλέψει με ένα συγκεκριμένο 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);
?>

Παράδειγμα για XML External Entity

Αυτό το παράδειγμα αντικατοπτρίζει τον XML κώδικα. Δείχνει πως να χρησιμοποιήσετε έναν external entity reference handler για να συμπεριλάβετε και να κάνετε parse και σε άλλα αρχεία, καθώς επίσης και πώς οι PIs μπορούν να εκτελεστούν, και έναν τρόπο για να καθοριστούν οι "έμπιστοι" PIs που περιέχουν κώδικα.

Τα XML αρχεία που μπορούν να χρησιμοποιηθούν σ'αυτό το παράδειγμα βρίσκονται κάτω από το παράδειγμα (xmltest.xml και xmltest2.xml.)

ÐáñÜäåéãìá 3. Πάραδειγμα για External Entity

<?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
"&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);

?>

ÐáñÜäåéãìá 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 id="about">
  <title>Σχετικά με αυτό το αρχείο</title>
  <para>
   <!-- this is a comment -->
   <?php print 'Hi!  This is PHP version '.phpversion(); ?>
  </para>
 </section>
</chapter>

Αυτό το αρχείο συμπεριλαμβάνεται από το xmltest.xml:

ÐáñÜäåéãìá 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>

Ðßíáêáò Ðåñéå÷ïìÝíùí
utf8_decode --  Μετατρέπει ένα string με ISO-8859-1 χαρακτήρες κωδικοποιημένο με UTF-8 σε single-byte ISO-8859-1.
utf8_encode -- Κωδικοποιεί ένα ISO-8859-1 string σε UTF-8
xml_error_string -- Παίρνει το error string του XML parser
xml_get_current_byte_index -- Παίρνει το τρέχον byte index για έναν XML parser
xml_get_current_column_number --  Παίρνει τον τρέχον αριθμό της στήλης για έναν XML parser
xml_get_current_line_number -- παίρνει στον τρέχον αριθμό γραμμή για έναν XML parser
xml_get_error_code -- παίρνει τον XML parser error code
xml_parse_into_struct -- Μεταγλωτίζει τα XML δεδομένα σε μια δομή πίνακα
xml_parse -- αρχίζει να μεταγλωτίζει ένα XML αρχείο
xml_parser_create_ns --  Δημιουργεί ένα XML parser με υποστήριξη namespace
xml_parser_create -- δημιουργεί έναν XML parser
xml_parser_free -- Ελευθερώνει έναν XML parser
xml_parser_get_option -- παίρνει τις επιλογές από έναν XML parser
xml_parser_set_option -- ορίζει επιλογές σε έναν XML parser
xml_set_character_data_handler -- ορίζει handler για δεδομένα χαρακτήρων
xml_set_default_handler -- ορίζει τον προκαθορισμένο handler
xml_set_element_handler -- ορίζει τα στοιχεία αρχής και τέλους των handlers
xml_set_end_namespace_decl_handler --  Ορίζει τον handler για δεδομένα χαρακτήρων
xml_set_external_entity_ref_handler -- ορίζει έναν external entity reference handler
xml_set_notation_decl_handler -- ορίζει τον notation declaration handler
xml_set_object -- Χρησιμοποιείστε τον XML Parser μέσα σε ένα object
xml_set_processing_instruction_handler --  Ορίζει τον processing instruction (PI) handler
xml_set_start_namespace_decl_handler --  Ορίζει τον character data handler
xml_set_unparsed_entity_decl_handler --  Ορίζει έναν αμεταγλώττιστο entity declaration handler