&reftitle.examples;

## XML Element Structure Example

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

### Show XML Element Structure

    <?php
    $file = "data.xml";
    $depth = array();

    function startElement($parser, $name, $attrs)
    {
        global $depth;

        if (!isset($depth[$parser])) {
            $depth[$parser] = 0;
        }

        for ($i = 0; $i < $depth[$parser]; $i++) {
            echo "  ";
        }
        echo "$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 Tag Mapping Example

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

    <?php
    $file = "data.xml";
    $map_array = array(
        "BOLD"     => "B",
        "EMPHASIS" => "I",
        "LITERAL"  => "TT"
    );

    function startElement($parser, $name, $attrs)
    {
        global $map_array;
        if (isset($map_array[$name])) {
            echo "<$map_array[$name]>";
        }
    }

    function endElement($parser, $name)
    {
        global $map_array;
        if (isset($map_array[$name])) {
            echo "</$map_array[$name]>";
        }
    }

    function characterData($parser, $data)
    {
        echo $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`.)

### External Entity Example

    <?php
    $file = "xmltest.xml";

    function trustedFile($file)
    {
        // only trust local files owned by ourselves
        if (!preg_match("@^([a-z]+)\:\/\/@i", $file)
            && fileowner($file) == getmyuid()) {
                return true;
        }
        return false;
    }

    function startElement($parser, $name, $attribs)
    {
        echo "&lt;<font color=\"#0000cc\">$name</font>";
        if (count($attribs)) {
            foreach ($attribs as $k => $v) {
                echo " <font color=\"#009900\">$k</font>=\"<font
                       color=\"#990000\">$v</font>\"";
            }
        }
        echo "&gt;";
    }

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

    function characterData($parser, $data)
    {
        echo "<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");
    }

    echo "<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)));
        }
    }
    echo "</pre>";
    echo "parse complete\n";
    xml_parser_free($xml_parser);

    ?>

### 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>About this Document</title>
      <para>
       <!-- this is a comment -->
       <?php echo 'Hi!  This is PHP version ' . phpversion(); ?>
      </para>
     </section>
    </chapter>

This file is included from `xmltest.xml`:

### xmltest2.xml

    <?xml version="1.0"?>
    <!DOCTYPE foo [
    <!ENTITY testEnt "test entity">
    ]>
    <foo>
       <element attrib="value"/>
       &testEnt;
       <?php echo "This is some more PHP code being executed."; ?>
    </foo>