Risoluzione Problema 1:
Il W3C defines: il significato dell'attributo xml:id
come un attributo ID in documenti XML e definisce l'elaborazione di questo attributo per identificare gli ID del assenza di convalida, senza recuperare risorse esterne e senza fare affidamento su un sottoinsieme interno.
In altre parole, quando si utilizza
$element->setAttribute('xml:id', 'test');
non è necessario chiamare setIdAttribute
, né specificare un DTD o schema. DOM riconoscerà l'attributo xml:id
quando utilizzato con getElementById
senza dover convalidare il documento o altro. Questo è l'approccio meno sforzo. Nota comunque che, a seconda del tuo sistema operativo e della versione di libxml, non avrai il getElementById
per funzionare.
Solving Problem2:
Anche con ID non essendo fetchable con getElementById
, si può ancora molto a prenderli con XPath:
$xpath->query('/pages/page[@id=1]');
sarebbe sicuramente lavorare. E si può anche recuperare i figli di prodotto per una specifica pagina direttamente:
$xpath->query('//pages/page[@id=1]/products');
Oltre a questo, c'è ben poco si può fare per rendere il codice DOM aspetto meno prolissa, perché è davvero un'interfaccia verbose. Deve essere, perché DOM is a language agnostic interface, again defined by the W3C.
EDIT dopo commento qui sotto
Si sta lavorando, come ho spiegato sopra. Ecco un caso di prova completo per te. La prima parte è per che scrive nuovi file XML con DOM. È qui che devi impostare l'attributo xml:id
. Si utilizza questo anziché l'attributo id regolare, non assegnato a un altro nome.
// 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;
Questo creerà un file XML in questo modo:
<?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>
Quando si leggere nel XML di nuovo, la nuova istanza DOM non sa più che avete dichiarato il non-namespace id
attributo come Attributo ID con setIdAttribute
. Sarà ancora in XML, ma l'attributo id sarà solo un attributo regolare. You have to be aware that ID attributes are special in XML.
// Load the XML we created above
$dom = new DOMDocument;
$dom->loadXML($xml);
Ora per alcuni test:
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
}
I lavori di cui sopra, perché un parser DOM compatibile deve riconoscere xml:id
è un attributo ID, indipendentemente da qualsiasi DTD o schema. Questo è spiegato nelle specifiche collegate sopra. Il motivo per cui viene generato lo spazio è perché, a causa dell'output formattato, esistono nodi DOMText tra il tag di apertura, i due tag di prodotto e i tag di chiusura, quindi stiamo ripetendo più di cinque nodi. Il concetto di nodo è fondamentale per capire quando si lavora 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
}
che questo non funziona, perché id
non è un attributo ID. Affinché il parser DOM lo riconosca come tale, è necessario un DTD o Schema e l'XML deve essere convalidato su di esso.
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 d'altra parte è letterale sugli attributi, il che significa che è possibile interrogare il DOM per l'elemento di pagina con l'attributo id
se getElementById
non è disponibile. Nota che per interrogare la pagina con ID p1, dovresti includere lo spazio dei nomi, ad es. @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
}
E come detto, è anche possibile utilizzare XPath per interrogare qualsiasi altra cosa nel documento.Questo non genererà spazi bianchi, perché restituirà solo gli elementi product
sotto la pagina con id p2.
È anche possibile attraversare l'intero DOM da un nodo. È una struttura ad albero. Dal momento che DOMNode è la classe più importante in DOM, è necessario acquisire familiarità con esso.
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'
Su un sidenote, sì, ho un refuso nel codice originale qui sopra. È product
non products
. Ma trovo difficilmente giustificabile affermare che il codice non funziona quando tutto ciò che devi cambiare è un s
. Sembra proprio troppo voler essere sfasato.
Suppongo che abbia appena fornito una descrizione della struttura del documento XML? Perché non è XML quello che hai postato (voglio solo essere sicuro;)). –
Ovviamente è solo un contorno. XML si convalida bene e sembra diverso dal mio codice: o – fabrik
le funzioni simplexml sarebbero troppo semplici per le tue esigenze? – stillstanding