Forum und email

Funções para analisar XML

Introdução

XML (eXtensible Markup Language) é um formato de dados para intercâmbio de documentos na Web. Ele é um padrão definido pela The World Wide Web consortium (W3C). Informações sobre XML e tecnologias relacionadas pode, ser encontradas em » https://www.w3.org/XML/.

Esta extensão do PHP implementa suporte para o James Clark's expat no PHP. Esta ferramenta permite que você analise, mas não valide, documentos XML. Ele suporta três source character encodings também fornecido pelo PHP: US-ASCII, ISO-8859-1 e UTF-8. UTF-16 não é suportado.

Esta extensão te permite criar analisadores XML e então definir manipuladores (handlers) para diferentes eventos XML. Cada analisador XML também tem alguns parâmetros que você pode ajustar.

Dependências

Esta extensão utiliza o expat compat layer por padrão. Ele pode usar também expat, que pode ser encontrado em » https://www.jclark.com/xml/expat.html. O Makefile que vem com o expat, por definição não constrói uma biblioteca, você pode usar as regras de 'make' para isso:

libexpat.a: $(OBJS)
    ar -rc $@ $(OBJS)
    ranlib $@
Um pacote dos fontes RPM do expat podem ser encontrados em » https://sourceforge.net/projects/expat/.

Instalação

Estas funções estão por definição habilitadas, usando o pacote expat library. Você pode desabilitar o suporte a XML com --disable-xml. Se você compilou o PHP como um módulo do Apache 1.3.9 ou mais novo, o PHP automaticamente utilizará o pacote expat library do Apache. Regularmente você não quer utilizar a configuração do pacote expat library do PHP --with-expat-dir=DIR, onde DIR apontaria para o diretório base de instalação do expat.

A versão para Windows do PHP tem suporte embutido para esta extensão. Você não precisa carregar nenhuma extensão adicional para utilizar essas funções.

Configurações em execução

Esta extensão não define nenhum parâmetro de configuração no php.ini.

Tipos Resource

xml

O recurso xml enquanto retornado por xml_parser_create() e xml_parser_create_ns() refere-se a uma instância do analisador xml para ser usada coms as funções fornecidas por esta extensão.

Constantes pré-definidas

As contantes abaixo são definidas por esta extensão e somente estarão disponíveis quando a extensão foi compilada com o PHP ou carregada dinamicamente durante a execução.

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)

Manipuladores (handlers) de Evento

Os manipuladores (handlers) de eventos de XML definidos são:

Manipuladores XML Suportados
função do PHP para definir o manipulador(handler) Descrição do evento
xml_set_element_handler() Eventos elementares são emitidos toda vez que o analisador XML o início ou o fim das tags. Há manipuladores (handlers) separadores para tags de início e tags de fim.
xml_set_character_data_handler() Dados de caractere são aproximadamente todo o conteúdo de documentos XML, incluindo espaços em branco entre as tags. Note que o analisador XML não adiciona ou remove qualquer espaço em branco, ele está pronto para a aplicação se você decidir que espaços em branco são significativos.
xml_set_processing_instruction_handler() Programadores de PHP já estariam familiarizados com instruções de processo (PIs). <?php ?> é uma instrução de processo, onde php é chamada de o "PI target". O tratamento destes são application-specific, exceto que todos os PI targets iniciados com "XML" estão reservados.
xml_set_default_handler() O que não vai para outro manipulador vai para o manipulador padrão. Você conseguirá coisas como o XML e declarações do tipo de documento no manipulador padrão.
xml_set_unparsed_entity_decl_handler() Este manipulador será chamado por uma declaração de um entity não analisada (NDATA).
xml_set_notation_decl_handler() Este manipulador é chamado pela declaração de uma nota.
xml_set_external_entity_ref_handler() Este manipulador é chamado quando o analisador XML encontra uma referência para uma entity geral analizada externamente. Isto pode ser uma referência para um arquivo ou URL, por examplo. Veja Um exemplo de entity externa para uma demonstração.

Case Folding

As funções de elementos do manipulador podem conseguir os nomes dos elementos case-folded. Case-folding é definida pelo padrão XML como "um processo aplicado para uma sequência de caracateres, em que aqueles identificados como minúsculos são substituidos pelos seus maiúsculos equivalentes". Em outras palavras, quando vai pro XML, case-folding simplesmente significa mudar pra maiúsculas.

Por definição, todos os nomes de elementos que são passados para as funções de manipulador são case-folded. Este comportamento pode ser perguntado e controlado pelo analisador XML com o xml_parser_get_option() e as funções xml_parser_set_option(), respectivamente.

Error Codes

As seguintes constantes são definidas para erros no código XML (conforme retornado por 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

Codificação de Caracter

A Extensão XML do PHP suporta o caracter » Unicode definido por character encodings (codificação de caracteres) diferentes. Há dois tipos de codificação de caracteres, source encoding e target encoding. A apresentação interna do PHP do documento é sempre codificada com UTF-8.

Source encoding é feita quando um documento XML é analisado. Em criando um analisador XML, um source encoding pode ser especificado (Esta codificação não poderá ser mudada após o tempo de vida do analisador XML). As codificações suportadas são ISO-8859-1, US-ASCII e UTF-8. O segundo são codificações single-byte, que significa que cada caractere é representado por um byte simples. UTF-8 pode codificar caracteres compostos por um número de bits variável (acima de 21) em um de seus 4 bytes. O source encoding padrão utilizado pelo PHP é ISO-8859-1.

Target encoding é feito quando o PHP passa dados para as funções do analisador XML. Quando um analisador XML é criado, o target encoding é definido igual ao source encoding, mas este pode ser mudado em qualquer ponto. O target encoding afetará dados de caracter tão bem como nome de tags e processando alvos da instrução.

Se o analisador XML encontra caracteres de fora da linha que seu source encoding é capaz de detalhar, ele retornará um erro.

Se PHP encontra caracteres no documento XML analisado que não podem ser detalhados selecionados com target encoding, os caracteres com problema serão "demoted". Atualmente, isto significa que tais caracteres serão substituidos por um sinal de interrogação.

Exemplos

Aqui estão alguns exemplos de scripts PHP analisando documentos XML.

Exemplo estruturado de elementos XML

Este primeiro exemplo mostra a estrutura de elementos iniciais num documento com distanciamento da margem.

Example#1 Mostra estrutura do elemento XML

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

function 
startElement($parser$name$attrs)
{
    global 
$depth;
    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($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);
?>

Exemplo arrumação de Tag XML

Example#2 Arrumar XML to HTML

Este exemplo arruma tags do documento XML diretamente para tags HTML. Elementos não encontrados no "array de arrumação" são ignorados. É claro, este exemplo trabalhará apenas com um tipo de documento XML específico.

<?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_parserXML_OPTION_CASE_FOLDINGtrue);
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($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);
?>

Exemplo XML de Entity externa

Este exemplo destaca o código XML. Ele ilusta como utilizar um analisador de referência a uma entity externa para incluir e analisar outros documentos, tão bem como PIs (instruções de processo) podem ser processadas, e uma forma de determinar "trust" para PIs contendo códigos.

Documentos XML que podem ser utilizados para este exemplo são encontrados abaixo do exemplo (xmltest.xml e xmltest2.xml.)

Example#3 Exemplo de Entity externa

<?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)
{
    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($data01) == "&" && substr($data, -11) == ";") {
        
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($fp4096)) {
            if (!
xml_parse($parser$datafeof($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_parserXML_OPTION_CASE_FOLDING1);
    
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($fp4096)) {
    if (!
xml_parse($xml_parser$datafeof($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);

?>

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>Título &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>Sobre este documento</title>
  <para>
   <!-- this is a comment -->
   <?php echo 'Hi!  This is PHP version '.phpversion(); ?>
  </para>
 </section>
</chapter>

Este arquivo está incluido de 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>

Índice