XML Wrangler es una biblioteca PHP simplista diseñada para facilitar la lectura y la escritura de XML. XML Wrangler se ha construido teniendo en cuenta la experiencia del desarrollador: puede leer cualquier tipo de archivo XML, incluso con espacios de nombres complejos e incluso archivos XML grandes. ¡También arrojará excepciones si el XML no es válido!
XML Wrangler se instala a través del compositor.
composer require saloonphp/xml-wrangler
Requiere Php 8.1+
La lectura de XML se puede hacer pasando la cadena o archivo XML al lector XML y utilizando uno de los muchos métodos para buscar y encontrar un elemento o valor específico. También puede convertir cada elemento en una matriz fácilmente transitable si lo prefiere. Si necesita acceder a los atributos en un elemento, puede usar el Element
DTO, que es una clase simple para acceder al contenido y los atributos. XML Wrangler proporciona métodos para iterar a través de múltiples elementos mientras solo mantiene un elemento en la memoria a la vez.
< breakfast_menu >
< food soldOut = " false " bestSeller = " true " >
< name >Belgian Waffles</ name >
< price >$5.95</ price >
< description >Two of our famous Belgian Waffles with plenty of real maple syrup</ description >
< calories >650</ calories >
</ food >
< food soldOut = " false " bestSeller = " false " >
< name >Strawberry Belgian Waffles</ name >
< price >$7.95</ price >
< description >Light Belgian waffles covered with strawberries and whipped cream</ description >
< calories >900</ calories >
</ food >
< food soldOut = " false " bestSeller = " true " >
< name >Berry-Berry Belgian Waffles</ name >
< price >$8.95</ price >
< description >Light Belgian waffles covered with an assortment of fresh berries and whipped cream</ description >
< calories >900</ calories >
</ food >
</ breakfast_menu >
<?php
use Saloon XmlWrangler XmlReader ;
$ reader = XmlReader :: fromString ( $ xml );
// Retrieve all values as one simple array
$ reader -> values (); // ['breakfast_menu' => [['name' => '...'], ['name' => '...'], ['name' => '...']]
// Use dot-notation to find a specific element
$ reader -> value ( ' food.0 ' )-> sole (); // ['name' => 'Belgian Waffles', 'price' => '$5.95', ...]
// Use the element method to get a simple Element DTO containing attributes and content
$ reader -> element ( ' food.0 ' )-> sole (); // Element::class
// Use XPath to query the XML
$ reader -> xpathValue ( ' //food[@bestSeller="true"]/name ' )-> get (); // ['Belgian Waffles', 'Berry-Berry Belgian Waffles']
// Use getAttributes() to get the attributes on the elements
$ reader -> element ( ' food.0 ' )-> sole ()-> getAttributes (); // ['soldOut' => false, 'bestSeller' => true]
// Use getContent() to get the contents of the elements
$ reader -> element ( ' food.0 ' )-> sole ()-> getContent (); // ['name' => 'Belgian Waffles', 'price' => '$5.95', ...]
Escribir XML es tan simple como definir una matriz PHP y usar claves y valores para definir elementos. Cuando necesite definir elementos con algunas características más, como atributos o espacios de nombres, puede usar el Element
DTO para definir elementos más avanzados.
<?php
use Saloon XmlWrangler Data Element ;
use Saloon XmlWrangler XmlWriter ;
$ writer = new XmlWriter ;
$ xml = $ writer -> write ( ' breakfast_menu ' , [
' food ' => [
[
' name ' => ' Belgian Waffles ' ,
' price ' => ' $5.95 ' ,
' description ' => ' Two of our famous Belgian Waffles with plenty of real maple syrup ' ,
' calories ' => ' 650 ' ,
],
[
' name ' => ' Strawberry Belgian Waffles ' ,
' price ' => ' $7.95 ' ,
' description ' => ' Light Belgian waffles covered with strawberries and whipped cream ' ,
' calories ' => ' 900 ' ,
],
// You can also use the Element class if you need to define elements with
// namespaces or with attributes.
Element :: make ([
' name ' => ' Berry-Berry Belgian Waffles ' ,
' price ' => ' $8.95 ' ,
' description ' => ' Light Belgian waffles covered with an assortment of fresh berries and whipped cream ' ,
' calories ' => ' 900 ' ,
])-> setAttributes ([ ' bestSeller ' => ' true ' ]),
],
]);
El código anterior creará el siguiente XML
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< breakfast_menu >
< food >
< name >Belgian Waffles</ name >
< price >$5.95</ price >
< description >Two of our famous Belgian Waffles with plenty of real maple syrup</ description >
< calories >650</ calories >
</ food >
< food >
< name >Strawberry Belgian Waffles</ name >
< price >$7.95</ price >
< description >Light Belgian waffles covered with strawberries and whipped cream</ description >
< calories >900</ calories >
</ food >
< food bestSeller = " true " >
< name >Berry-Berry Belgian Waffles</ name >
< price >$8.95</ price >
< description >Light Belgian waffles covered with an assortment of fresh berries and whipped cream</ description >
< calories >900</ calories >
</ food >
</ breakfast_menu >
Esta sección sobre la documentación es para usar el lector XML.
El lector XML puede aceptar una variedad de tipos de entrada. Puede usar una cadena XML, archivo o proporcionar un recurso. También puede leer el XML directamente desde una respuesta de PSR (como de Guzzle) o una respuesta de salón.
use Saloon XmlWrangler XmlReader ;
$ reader = XmlReader :: fromString ( ' <?xml version="1.0" encoding="utf-8"?><breakfast_menu>... ' );
$ reader = XmlReader :: fromFile ( ' path/to/file.xml ' );
$ reader = XmlReader :: fromStream ( fopen ( ' path/to/file.xml ' , ' rb ' );
$ reader = XmlReader :: fromPsrResponse ( $ response );
$ reader = XmlReader :: fromSaloonResponse ( $ response );
ADVERTENCIA Debido a las limitaciones de la clase PHP XMLReader subyacente, los métodos
fromStream
,fromPsrResponse
yfromSaloon
crearán un archivo temporal en su máquina/servidor para leer desde el cual se eliminará automáticamente cuando el lector sea destruido. Deberá asegurarse de tener suficiente almacenamiento en su máquina para usar este método.
Puede usar los métodos de elements
y values
para convertir todo el documento XML en una matriz. Si desea una matriz de valores, use el método values
, pero si necesita acceder a los atributos en los elementos, el método elements
devolverá una matriz de DTO de Element
.
$ reader = XmlReader :: fromString (...);
$ elements = $ reader -> elements (); // Array of `Element::class` DTOs
$ values = $ reader -> values (); // Array of values.
Tenga en cuenta que si está leyendo un archivo XML grande, debe usar los métodos de
element
ovalue
en su lugar. Estos métodos pueden iterar a través de archivos XML grandes sin quedarse sin memoria.
Puede usar el método value
para obtener el valor de un elemento específico. Puede usar la notación de puntos para buscar elementos infantiles. También puede usar números enteros para encontrar posiciones específicas de múltiples elementos. Este método busca a través de todo el cuerpo XML de una manera eficiente en memoria.
Este método devolverá una clase LazyQuery
que tiene diferentes métodos para recuperar los datos.
$ reader = XmlReader :: fromString ( '
<?xml version="1.0" encoding="utf-8"?>
<person>
<name>Sammyjo20</name>
<favourite-songs>
<song>Luke Combs - When It Rains It Pours</song>
<song>Sam Ryder - SPACE MAN</song>
<song>London Symfony Orchestra - Starfield Suite</song>
</favourite-songs>
</person>
' );
$ reader -> value ( ' person.name ' )-> sole () // ' Sammyjo20 '
$ reader -> value ( ' song ' )-> get (); // ['Luke Combs - When It Rains It Pours', 'Sam Ryder - SPACE MAN', ...]
$ reader -> value ( ' song.2 ' )-> sole (); // 'London Symfony Orchestra - Starfield Suite'
Puede usar el método element
para buscar un elemento específico. Este método proporcionará una clase Element
que contiene el valor y los atributos. Puede usar la notación de puntos para buscar elementos infantiles. También puede usar números enteros para encontrar posiciones específicas de múltiples elementos. Este método busca a través de todo el cuerpo XML de manera eficiente en memoria.
Este método devolverá una clase LazyQuery
que tiene diferentes métodos para recuperar los datos.
$ reader = XmlReader :: fromString ( '
<?xml version="1.0" encoding="utf-8"?>
<person>
<name>Sammyjo20</name>
<favourite-songs>
<song>Luke Combs - When It Rains It Pours</song>
<song>Sam Ryder - SPACE MAN</song>
<song>London Symfony Orchestra - Starfield Suite</song>
</favourite-songs>
</person>
' );
$ reader -> element ( ' name ' )-> sole (); // Element('Sammyjo20')
$ reader -> element ( ' song ' )-> get (); // [Element('Luke Combs - When It Rains It Pours'), Element('Sam Ryder - SPACE MAN'), ...]
$ reader -> element ( ' song.2 ' )-> sole (); // Element('London Symfony Orchestra - Starfield Suite')
A veces es más fácil atravesar un documento XML cuando no tiene que preocuparse por los espacios de nombres y los prefijos de los elementos. Si desea eliminarlos, puede usar el método removeNamespaces()
en el lector.
$ reader = XmlReader :: fromString (...);
$ reader -> removeNamespaces ();
Al buscar en un archivo grande, puede usar los métodos lazy
o collectLazy
que devolverán un generador de resultados solo manteniendo un elemento en la memoria a la vez.
$ names = $ reader -> element ( ' name ' )-> lazy ();
foreach ( $ names as $ name ) {
//
}
Si está utilizando Laravel, puede usar los métodos collect
y collectLazy
que convertirán los elementos en una colección de Laravel/colección perezosa. Si no está utilizando Laravel, puede instalar el paquete illuminate/collections
a través del compositor para agregar esta funcionalidad.
$ names = $ reader -> value ( ' name ' )-> collect ();
$ names = $ reader -> value ( ' name ' )-> collectLazy ();
A veces es posible que desee buscar un elemento o valor específico donde el elemento contenga un atributo específico. Puede hacerlo proporcionando un segundo argumento al método value
o element
. Esto buscará en el último elemento los atributos y volverá si coinciden.
$ reader = XmlReader :: fromString ( '
<?xml version="1.0" encoding="utf-8"?>
<person>
<name>Sammyjo20</name>
<favourite-songs>
<song>Luke Combs - When It Rains It Pours</song>
<song>Sam Ryder - SPACE MAN</song>
<song recent="true">London Symfony Orchestra - Starfield Suite</song>
</favourite-songs>
</person>
' );
$ reader -> element ( ' song ' , [ ' recent ' => ' true ' ])-> sole (); // Element('London Symfony Orchestra - Starfield Suite')
$ reader -> value ( ' song ' , [ ' recent ' => ' true ' ])-> sole (); // 'London Symfony Orchestra - Starfield Suite'
XPATH es una forma fantástica de buscar a través de XML. Con una cadena, puede buscar un elemento específico, con atributos o índices específicos. Si está interesado en aprender XPATH, puede hacer clic aquí para obtener una hoja de trucos útil.
Puede usar el método xpathValue
para encontrar el valor de un elemento específico con una consulta XPath. Este método devolverá una clase Query
que tiene diferentes métodos para recuperar los datos.
<?php
$ reader = XmlReader :: fromString (...);
$ reader -> xpathValue ( ' //person/favourite-songs/song[3] ' )-> sole (); // 'London Symfony Orchestra - Starfield Suite'
Puede usar el método xpathElement
para encontrar un elemento específico con una consulta XPath. Este método devolverá una clase Query
que tiene diferentes métodos para recuperar los datos.
<?php
$ reader = XmlReader :: fromString (...);
$ reader -> xpathElement ( ' //person/favourite-songs/song[3] ' )-> sole (); // Element('London Symfony Orchestra - Starfield Suite')
Advertencia debido a limitaciones con XPATH: los métodos anteriores utilizados para consultar con XPath no son seguros de memoria y pueden no ser adecuados para grandes documentos XML.
Es posible que se encuentre con un documento XML que contiene un atributo xmlns
no preferido, como este:
< container xmlns = " http://example.com/xml-wrangler/person " xmlns : xsi = " http://www.w3.org/2001/XMLSchema-instance " />
Cuando esto sucede, XML Wrangler eliminará automáticamente estos espacios de nombres no preferidos para mejorar la compatibilidad. Si desea mantener estos espacios de nombres, puede usar setXpathNamespaceMap
para asignar cada espacio de nombres XML sin prepárselo.
$ reader = XmlReader :: fromString (...);
$ reader -> setXpathNamespaceMap ([
' root ' => ' http://example.com/xml-wrangler/person ' ,
]);
$ reader -> xpathValue ( ' //root:person/root:favourite-songs/root:song[3] ' )-> sole ();
Esta sección sobre la documentación es para usar el escritor XML.
El uso más básico del lector es usar teclas de cadena para los nombres y valores de los elementos para los valores del elemento. El escritor acepta matrices infinitamente anidadas para elementos anidados.
use Saloon XmlWrangler XmlWriter ;
$ xml = XmlWriter :: make ()-> write ( ' root ' , [
' name ' => ' Sam ' ,
' twitter ' => ' @carre_sam ' ,
' facts ' => [
' favourite-song ' => ' Luke Combs - When It Rains It Pours '
],
]);
El código anterior se convertirá en el siguiente XML
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< root >
< name >Sam</ name >
< twitter >@carre_sam</ twitter >
< facts >
< favourite-song >Luke Combs - When It Rains It Pours</ favourite-song >
</ facts >
</ root >
Al escribir XML, a menudo deberá definir atributos y espacios de nombres en sus elementos. Puede usar la clase Element
en la matriz de XML para agregar un elemento con un atributo o espacio de nombres. Puede mezclar la clase Element
con otras matrices y valores de cadena.
use Saloon XmlWrangler XmlWriter ;
use Saloon XmlWrangler Data Element ;
$ xml = XmlWriter :: make ()-> write ( ' root ' , [
' name ' => ' Sam ' ,
' twitter ' => Element :: make ( ' @carre_sam ' )-> addAttribute ( ' url ' , ' https://twitter.com/@carre_sam ' ),
' facts ' => [
' favourite-song ' => ' Luke Combs - When It Rains It Pours '
],
' soap:custom-namespace ' => Element :: make ()-> addNamespace ( ' soap ' , ' http://www.w3.org/2003/05/soap-envelope ' ),
]);
Esto dará como resultado el siguiente XML
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< root >
< name >Sam</ name >
< twitter url = " https://twitter.com/@carre_sam " >@carre_sam</ twitter >
< facts >
< favourite-song >Luke Combs - When It Rains It Pours</ favourite-song >
</ facts >
< soap : custom-namespace xmlns : soap = " http://www.w3.org/2003/05/soap-envelope " />
</ root >
A menudo necesitará definir una variedad de elementos. Puede hacerlo simplemente proporcionando una variedad de valores o clases de elementos.
use Saloon XmlWrangler XmlWriter ;
use Saloon XmlWrangler Data Element ;
$ xml = XmlWriter :: make ()-> write ( ' root ' , [
' name ' => ' Luke Combs ' ,
' songs ' => [
' song ' => [
' Fast Car ' ,
' The Kind Of Love We Make ' ,
' Beautiful Crazy ' ,
Element :: make ( ' She Got The Best Of Me ' )-> addAttribute ( ' hit ' , ' true ' ),
],
],
]);
Esto dará como resultado el siguiente XML
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< root >
< name >Luke Combs</ name >
< songs >
< song >Fast Car</ song >
< song >The Kind Of Love We Make</ song >
< song >Beautiful Crazy</ song >
< song hit = " true " >She Got The Best Of Me</ song >
</ songs >
</ root >
A veces es posible que deba cambiar el nombre del elemento raíz. Esto se puede personalizar como el primer argumento del método write
.
$ xml = XmlWriter :: make ()-> write ( ' custom-root ' , [...])
Si desea agregar atributos y espacios de nombres al elemento raíz, también puede usar una clase RootElement
.
use Saloon XmlWrangler Data RootElement ;
$ rootElement = RootElement :: make ( ' root ' )-> addNamespace ( ' soap ' , ' http://www.w3.org/2003/05/soap-envelope ' );
$ xml = XmlWriter :: make ()-> write ( $ rootElement , [...])
Si necesita agregar una etiqueta CDATA, puede usar la clase CDATA
.
use Saloon XmlWrangler Data CDATA ; use Saloon XmlWrangler XmlWriter ;
use Saloon XmlWrangler Data Element ;
$ xml = XmlWriter :: make ()-> write ( ' root ' , [
' name ' => ' Sam ' ,
' custom ' => CDATA :: make ( ' Here is some CDATA content! ' ),
]);
Esto dará como resultado el siguiente XML
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< root >
< name >Sam</ name >
< custom > <![CDATA[ Here is some CDATA content! ]]> </ custom >
</ root >
A veces puede tener una parte de XML que reutilizará en varias solicitudes XML en su aplicación. Con XML Wrangler, puede crear elementos "compuestos" donde puede definir su contenido XML en una clase que puede reutilizar en su aplicación. Extienda la clase Element
y use el método compose
estática protegida.
<?php
use Saloon XmlWrangler XmlWriter ;
use Saloon XmlWrangler Data Element ;
class BelgianWafflesElement extends Element
{
protected function compose (): void
{
$ this
-> setAttributes ([
' soldOut ' => ' false ' ,
' bestSeller ' => ' true ' ,
])
-> setContent ([
' name ' => ' Belgian Waffles ' ,
' price ' => ' $5.95 ' ,
' description ' => ' Two of our famous Belgian Waffles with plenty of real maple syrup ' ,
' calories ' => ' 650 ' ,
]);
}
}
$ writer = XmlWriter :: make ()-> write ( ' root ' , [
' food ' => new BelgianWafflesElement ,
]);
Esto dará como resultado un XML como este:
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< breakfast_menu >
< food soldOut = " false " bestSeller = " true " >
< name >Belgian Waffles</ name >
< price >$5.95</ price >
< description >Two of our famous Belgian Waffles with plenty of real maple syrup</ description >
< calories >650</ calories >
</ food >
</ breakfast_menu >
La codificación XML predeterminada es utf-8
, la versión predeterminada de XML es 1.0
, y el Standalone predeterminado es null
(los analizadores XML interpretan ningún atributo independiente lo mismo que false
). Si desea personalizar esto, puede con los métodos setXmlEncoding
, setXmlVersion
y setXmlStandalone
en el escritor.
use Saloon XmlWrangler XmlWriter ;
$ writer = new XmlWriter ();
$ writer -> setXmlEncoding ( ' ISO-8859-1 ' );
$ writer -> setXmlVersion ( ' 2.0 ' );
$ writer -> setXmlStandalone ( true );
// $writer->write(...);
Lo que da como resultado la declaración XML <?xml version="2.0" encoding="ISO-8859-1" standalone="yes"?>
.
Puede agregar una "instrucción de procesamiento" personalizada al XML utilizando el método addProcessingInstruction
.
use Saloon XmlWrangler XmlWriter ;
$ writer = new XmlWriter ();
$ writer -> addProcessingInstruction ( ' xml-stylesheet ' , ' type="text/xsl" href="base.xsl" ' );
$ xml = $ writer -> write ( ' root ' , [ ' name ' => ' Sam ' ]);
Esto dará como resultado el siguiente XML
<? xml version = " 1.0 " encoding = " utf-8 " ?>
<? xml-stylesheet type = " text/xsl " href = " base.xsl " ?>
< root >
< name >Sam</ name >
</ root >
Por defecto, el XML escrito no está minificado. Puede proporcionar el tercer argumento al método write
para minificar el XML.
use Saloon XmlWrangler XmlWriter ;
$ xml = XmlWriter :: make ()-> write ( ' root ' , [...], minified: true );
XML Wrangler es un envoltorio simple alrededor de dos bibliotecas realmente poderosas que hacen gran parte del trabajo preliminar. ¡Ambas bibliotecas son fantásticas y merecen una estrella!