Come distinguere tra elemento vuoto e string di dimensione nulla in DOMDocument?

Ho problemi a caricare documenti XML in DOM preservando tag vuoti e stringhe di dimensione nulla. Ecco l'esempio:

$doc = new DOMDocument("1.0", "utf-8"); $root = $doc->createElement("root"); $doc->appendChild($root); $element = $doc->createElement("element"); $root->appendChild($element); echo $doc->saveXML(); 

produce il seguente XML:

 <?xml version="1.0" encoding="utf-8"?> <root><element/></root> 

Elemento vuoto, esattamente come previsto. Ora aggiungiamo il nodo di text vuoto nell'elemento.

 $doc = new DOMDocument("1.0", "utf-8"); $root = $doc->createElement("root"); $doc->appendChild($root); $element = $doc->createElement("element"); $element->appendChild($doc->createTextNode("")); $root->appendChild($element); echo $doc->saveXML(); 

produce il seguente XML:

 <?xml version="1.0" encoding="utf-8"?> <root><element></element></root> 

Elemento non vuoto con string di dimensione nulla. Buona! Ma quando sto cercando di fare:

 $doc = new DOMDocument(); $doc->loadXML($xml); echo $doc->saveXML($doc); 

su questi documenti XML ottengo sempre

 <?xml version="1.0" encoding="utf-8"?> <root><element/></root> 

cioè la string di dimensione nulla viene rimossa e viene caricato solo l'elemento vuoto. Credo che accada su loadXML (). C'è un modo per convincere DOMDocument loadXML () a non convertire una string di dimensione nulla in un elemento vuoto? Sarebbe preferibile se il DOM avesse TextNode con string di dimensione nulla come figlio dell'elemento.

La soluzione è necessaria per essere in DOM PHP a causa del modo in cui ciò che accadrà ai dati caricati ulteriormente.

Il problema di distinguere tra questi due è che quando DOMDocument carica il documento serializzato XML, segue solo le specifiche.

In base al libro, in <element></element> non vi è alcun nodo di text vuoto in quell'elemento – che è ciò che altri hanno già commentato.

Tuttavia DOMDocument funziona perfettamente se si inserisce un nodo di text vuoto proprio lì. Quindi puoi facilmente distinguere tra un tag che si chiude automaticamente (senza figli) e un elemento vuoto (che ha un figlio, un nodo di text vuoto).

Quindi, come inserire quei nodes di text vuoti? Ad esempio, utilizzando la libreria XMLReaderIterator basata su XMLReader , in particolare la DOMReadingIteration , che è in grado di creare il documento, offrendo al contempo ciascun nodo XMLReader corrente per l'interazione:

 $doc = new DOMDocument(); $iterator = new DOMReadingIteration($doc, $reader); foreach ($iterator as $index => $value) { // Preserve empty elements as non-self-closing by making them non-empty with a single text-node // children that has zero-length text if ($iterator->isEndElementOfEmptyElement()) { $iterator->getLastNode()->appendChild(new DOMText('')); } } echo $doc->saveXML(); 

Questo dà il tuo contributo:

 <?xml version="1.0" encoding="utf-8"?> <root><element></element></root> 

Questa output:

 <?xml version="1.0"?> <root><element></element></root> 

Senza obblighi. Un bel build DOMDocument . L'esempio è da examples/read-into-dom.php e una prova eccellente che non è un problema quando si carica il documento tramite XMLReader e si ha a che fare con quel singolo caso speciale che si ha.

Qui non c'è differenza per il parser XML di caricamento. Il DOM è esattamente lo stesso.

Se si carica / salva un formato XML che presenta un problema con tag vuoti, è ansible utilizzare un'opzione per evitare i tag vuoti al salvataggio:

 $dom = new DOMDocument(); $dom->appendChild($dom->createElement('foo')); echo $dom->saveXml(); echo "\n"; echo $dom->saveXml(NULL, LIBXML_NOEMPTYTAG); 

Produzione:

 <?xml version="1.0"?> <foo/> <?xml version="1.0"?> <foo></foo> 

È ansible ingannare i processri XSLT affinché non utilizzino elementi auto-chiudenti, fingendo un xsl:value-of inserire una variabile, ma quella variabile è una string vuota '' .

Ingresso:

 <?xml version="1.0" encoding="utf-8"?> <root> <foo> <bar some="value"></bar> <self-closing attr="foobar" val="3.5"/> </foo> <goo> <gle> <nope/> </gle> </goo> </root> 

Foglio di stile:

 <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="*[not(node())]"> <xsl:copy> <xsl:for-each select="@*"> <xsl:attribute name="{name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> <xsl:value-of select="''"/> </xsl:copy> </xsl:template> </xsl:stylesheet> 

Produzione:

 <?xml version="1.0" encoding="utf-8"?> <root> <foo> <bar some="value"></bar> <self-closing attr="foobar" val="3.5"></self-closing> </foo> <goo> <gle> <nope></nope> </gle> </goo> </root> 

Per risolvere questo problema in PHP senza l'utilizzo di un processre XSLT, posso solo pensare di aggiungere nodes di text vuoti a tutti gli elementi senza figli (come fai tu nella creazione dell'XML).