resolución de problemas 1:
El W3C defines: el significado del atributo xml:id
como un atributo ID en los documentos XML y define el procesamiento de este atributo para identificar ID en el ausencia de validación, sin buscar recursos externos y sin depender de un subconjunto interno.
En otras palabras, cuando se utiliza
$element->setAttribute('xml:id', 'test');
que no es necesario llamar a setIdAttribute
, ni especificar una DTD o esquema. DOM reconocerá el atributo xml:id
cuando se usa con getElementById
sin tener que validar el documento ni nada. Este es el enfoque de menor esfuerzo. Sin embargo, tenga en cuenta que, dependiendo de su sistema operativo y la versión de libxml, no obtendrá getElementById
para funcionar.
Resolver Problem2:
Incluso con los ID de no ser fetchable con getElementById
, puede todavía muy buscarlos con XPath:
$xpath->query('/pages/page[@id=1]');
sin duda trabajar. Y también se puede recuperar a los niños de productos para una página específica directamente:
$xpath->query('//pages/page[@id=1]/products');
Aparte de esto, hay muy poco que se pueda hacer para que DOM mirada código de menos detallado, porque realmente es una interfaz detallado. Tiene que ser así, porque DOM is a language agnostic interface, again defined by the W3C.
Edición después de comentarios a continuación
está trabajando como he explicado anteriormente. Aquí hay un caso de prueba completo para usted. La primera parte es para escribiendo nuevos archivos XML con DOM. Ahí es donde debe establecer el atributo xml:id
. Utiliza esto en lugar del atributo de id regular, sin nombre de espacio.
// Setup
$dom = new DOMDocument;
$dom->formatOutput = TRUE;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML('<pages/>');
// How to set a valid id attribute when not using a DTD or Schema
$page1 = $dom->createElement('page');
$page1->setAttribute('xml:id', 'p1');
$page1->appendChild($dom->createElement('product', 'foo1'));
$page1->appendChild($dom->createElement('product', 'foo2'));
// How to set an ID attribute that requires a DTD or Schema when reloaded
$page2 = $dom->createElement('page');
$page2->setAttribute('id', 'p2');
$page2->setIdAttribute('id', TRUE);
$page2->appendChild($dom->createElement('product', 'bar1'));
$page2->appendChild($dom->createElement('product', 'bar2'));
// Appending pages and saving XML
$dom->documentElement->appendChild($page1);
$dom->documentElement->appendChild($page2);
$xml = $dom->saveXML();
unset($dom, $page1, $page2);
echo $xml;
Esto creará un archivo XML como esto:
<?xml version="1.0"?>
<pages>
<page xml:id="p1">
<product>foo1</product>
<product>foo2</product>
</page>
<page id="p2">
<product>bar1</product>
<product>bar2</product>
</page>
</pages>
Cuando leer en el XML de nuevo, la nueva instancia DOM ya no se sabe que haya declarado la no namespaced id
atributo como Atributo ID con setIdAttribute
. Todavía estará en XML, pero el atributo id solo será un atributo regular. You have to be aware that ID attributes are special in XML.
// Load the XML we created above
$dom = new DOMDocument;
$dom->loadXML($xml);
Ahora para algunas pruebas:
echo "\n\n GETELEMENTBYID RETURNS ELEMENT WITH XML:ID \n\n";
foreach($dom->getElementById('p1')->childNodes as $product) {
echo $product->nodeValue; // Will output foo1 and foo2 with whitespace
}
Los trabajos anteriores, debido a que un analizador compatible DOM tiene que reconocer xml:id
es un atributo ID, independientemente de cualquier DTD o esquema. Esto se explica en las especificaciones vinculadas anteriormente. El motivo por el que se generan espacios en blanco es porque, debido a la salida formateada, hay nodos DOMText entre la etiqueta de apertura, las dos etiquetas de producto y las etiquetas de cierre, por lo que estamos iterando en cinco nodos. El concepto de nodo es crucial para entender cuando se trabaja con XML.
echo "\n\n GETELEMENTBYID CANNOT FETCH NORMAL ID \n\n";
foreach($dom->getElementById('p2')->childNodes as $product) {
echo $product->nodeValue; // Will output a NOTICE and a WARNING
}
Lo anterior no funcionará, porque id
no es un atributo ID. Para que el analizador DOM lo reconozca como tal, necesita una DTD o un Esquema y el XML debe validarse en su contra.
echo "\n\n XPATH CAN FETCH NORMAL ID \n\n";
$xPath = new DOMXPath($dom);
$page2 = $xPath->query('/pages/page[@id="p2"]')->item(0);
foreach($page2->childNodes as $product) {
echo $product->nodeValue; // Will output bar1 and bar2
}
XPath por el contrario es literal sobre los atributos, lo que significa que se puede consultar el DOM para el elemento de página con el atributo id
si getElementById
no está disponible. Tenga en cuenta que para consultar la página con ID p1, debe incluir el espacio de nombre, p. @xml:id="p1"
.
echo "\n\n XPATH CAN FETCH PRODUCTS FOR PAGE WITH ID \n\n";
$xPath = new DOMXPath($dom);
foreach($xPath->query('/pages/page[@id="p2"]/product') as $product) {
echo $product->nodeValue; // Will output bar1 and bar2 w\out whitespace
}
Y como he dicho, también puede usar XPath para consultar cualquier otra cosa en el documento.Este no generará espacio en blanco, ya que solo devolverá los elementos product
debajo de la página con id p2.
También puede recorrer todo el DOM desde un nodo. Es una estructura de árbol. Como DOMNode es la clase más importante en DOM, desea familiarizarse con ella.
echo "\n\n TRAVERSING UP AND DOWN \n\n";
$product = $dom->getElementsByTagName('product')->item(2);
echo $product->tagName; // 'product'
echo $dom->saveXML($product); // '<product>bar1</product>'
// Going from bar1 to foo1
$product = $product->parentNode // Page Node
->parentNode // Pages Node
->childNodes->item(1) // Page p1
->childNodes->item(1); // 1st Product
echo $product->nodeValue; // 'foo1'
// from foo1 to foo2 it is two(!) nodes because the XML is formatted
echo $product->nextSibling->nodeName; // '#text' with whitespace and linebreak
echo $product->nextSibling->nextSibling->nodeName; // 'product'
echo $product->nextSibling->nextSibling->nodeValue; // 'foo2'
En una nota alla, sí, tengo un error ortográfico en el código original de arriba. Es product
no products
. Pero me parece difícil justificar que el código no funciona cuando todo lo que tiene que cambiar es un s
. Eso solo se siente como querer ser cuchareado.
Supongo que acaba de dar un resumen de la estructura de su documento XML? Porque no es XML lo que has publicado (solo quiero estar seguro;)). –
Por supuesto, es solo un esquema. XML valida bien y se ve bien a diferencia de mi código: o – fabrik
¿las funciones de simplexml serían demasiado simples para sus necesidades? – stillstanding