Soy la función a continuación, estoy luchando para generar el DOMDocument sin que agregue los envoltorios XML, HTML, body y p antes de la salida del contenido. La solución sugerida:
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
Solo funciona cuando el contenido no tiene elementos de nivel de bloque en su interior. Sin embargo, cuando lo hace, como en el ejemplo siguiente con el elemento h1, la salida resultante de saveXML se trunca a ...
<p> Si te gusta </p>
Me han señalado esta publicación como una posible solución alternativa, pero no puedo entender cómo implementarla en esta solución (consulte los intentos comentados a continuación).
¿Alguna sugerencia?
function rseo_decorate_keyword($postarray) {
global $post;
$keyword = "Jasmine Tea"
$content = "If you like <h1>jasmine tea</h1> you will really like it with Jasmine Tea flavors. This is the last ocurrence of the phrase jasmine tea within the content. If there are other instances of the keyword jasmine tea within the text what happens to jasmine tea."
$d = new DOMDocument();
@$d->loadHTML($content);
$x = new DOMXpath($d);
$count = $x->evaluate("count(//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and (ancestor::b or ancestor::strong)])");
if ($count > 0) return $postarray;
$nodes = $x->query("//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and not(ancestor::h1) and not(ancestor::h2) and not(ancestor::h3) and not(ancestor::h4) and not(ancestor::h5) and not(ancestor::h6) and not(ancestor::b) and not(ancestor::strong)]");
if ($nodes && $nodes->length) {
$node = $nodes->item(0);
// Split just before the keyword
$keynode = $node->splitText(strpos($node->textContent, $keyword));
// Split after the keyword
$node->nextSibling->splitText(strlen($keyword));
// Replace keyword with <b>keyword</b>
$replacement = $d->createElement('strong', $keynode->textContent);
$keynode->parentNode->replaceChild($replacement, $keynode);
}
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
// $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->item(1));
// $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->childNodes);
return $postarray;
}
fuente
DOMDocument
que también afecta el código en esta respuesta. Afaik,DOMDocument
siempre interpreta los datos de entrada como latin-1 a menos que la entrada especifique un juego de caracteres diferente . En otras palabras: la<meta charset="…">
etiqueta parece ser necesaria para datos de entrada que no son latin-1. De lo contrario, la salida se interrumpirá para, por ejemplo, caracteres multibyte UTF-8.Simplemente elimine los nodos directamente después de cargar el documento con loadHTML ():
fuente
<!DOCTYPE
funciona. La segunda línea se rompe si<body>
tiene más de una nota secundaria.Úselo en su
saveXML()
lugar y pásele el elemento documentElement como argumento.http://php.net/domdocument.savexml
fuente
saveHTML
así ( ejemplo )loadHTML
libxml usa el módulo analizador HTML y eso insertará el esqueleto HTML que falta. En consecuencia,$dom->documentElement
será el elemento HTML raíz. He arreglado tu código de ejemplo. Ahora debería hacer lo que Scott está pidiendo.El problema con la respuesta principal es que
LIBXML_HTML_NOIMPLIED
es inestable .Puede reordenar elementos (en particular, mover la etiqueta de cierre del elemento superior a la parte inferior del documento), agregar
p
etiquetas aleatorias y tal vez una variedad de otras cuestiones [1] . Puede eliminar las etiquetashtml
ybody
por usted, pero a costa de un comportamiento inestable. En producción, eso es una señal de alerta. En breve:No lo use
LIBXML_HTML_NOIMPLIED
. En su lugar, utilicesubstr
.Piénsalo. Las longitudes de
<html><body>
y</body></html>
son fijas y en ambos extremos del documento; sus tamaños nunca cambian, ni tampoco sus posiciones. Esto nos permite usarsubstr
para cortarlos:( ¡SIN EMBARGO, ESTA NO ES LA SOLUCIÓN FINAL! Vea a continuación la respuesta completa , siga leyendo para conocer el contexto)
Cortamos
12
desde el inicio del documento porque<html><body>
= 12 caracteres (<<>>+html+body
= 4 + 4 + 4), y retrocedemos y cortamos 15 del final porque\n</body></html>
= 15 caracteres (\n+//+<<>>+body+html
= 1 + 2 + 4 + 4 + 4)Tenga en cuenta que todavía uso
LIBXML_HTML_NODEFDTD
omitir la!DOCTYPE
inclusión. Primero, esto simplifica lasubstr
eliminación de las etiquetas HTML / BODY. En segundo lugar, no eliminamos el tipo de documento consubstr
porque no sabemos si "default doctype
" siempre tendrá una longitud fija. Pero, lo más importante,LIBXML_HTML_NODEFDTD
evita que el analizador DOM aplique un tipo de documento que no sea HTML5 al documento, lo que al menos evita que el analizador trate los elementos que no reconoce como texto suelto.Sabemos con certeza que las etiquetas HTML / BODY son de longitudes y posiciones fijas, y sabemos que las constantes como
LIBXML_HTML_NODEFDTD
nunca se eliminan sin algún tipo de aviso de desaprobación, por lo que el método anterior debería aplicarse en el futuro, PERO ...... la única advertencia es que la implementación DOM podría cambiar la forma en que las etiquetas HTML / BODY se colocan dentro del documento, por ejemplo, eliminando la nueva línea al final del documento, agregando espacios entre las etiquetas o agregando nuevas líneas.
Esto puede remediarse buscando las posiciones de las etiquetas de apertura y cierre
body
, y usando esas compensaciones para nuestras longitudes para recortar. Usamosstrpos
ystrrpos
para encontrar las compensaciones de la parte delantera y trasera, respectivamente:Para terminar, una repetición de la respuesta final a prueba de futuro :
Sin doctype, sin etiqueta html, sin etiqueta de cuerpo. Solo podemos esperar que el analizador DOM reciba una nueva capa de pintura pronto y podamos eliminar más directamente estas etiquetas no deseadas.
fuente
$html = $dom -> saveHTML();
lugar de$dom -> saveHTML();
repetidamente?Un buen truco es usar
loadXML
y luegosaveHTML
. Las etiquetashtml
ybody
se insertan en elload
escenario, no en elsave
escenario.Tenga en cuenta que esto es un poco hacky y debería usar la respuesta de Jonah si puede hacer que funcione.
fuente
utilizar DOMDocumentFragment
fuente
Estamos en 2017 y para esta pregunta de 2011 no me gusta ninguna de las respuestas. Muchas expresiones regulares, clases grandes, loadXML, etc.
Fácil solución que resuelve los problemas conocidos:
Fácil, simple, sólido, rápido. Este código funcionará con respecto a las etiquetas HTML y la codificación como:
Si alguien encuentra un error, dígalo, lo usaré yo mismo.
Editar , Otras opciones válidas que funcionan sin errores (muy similares a las ya dadas):
Puede agregar cuerpo usted mismo para evitar cualquier cosa extraña en el furure.
Treinta opción:
fuente
mb_convert_encoding
y, en su lugar, agregando<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>
y modificando ensubstr
consecuencia. Por cierto, la tuya es la solución más elegante aquí. Voto a favor.Llegué un poco tarde al club, pero no quería no compartir un método que descubrí. En primer lugar, tengo las versiones correctas para que loadHTML () acepte estas buenas opciones, pero
LIBXML_HTML_NOIMPLIED
no funcionó en mi sistema. Además, los usuarios informan problemas con el analizador (por ejemplo, aquí y aquí ).La solución que creé en realidad es bastante simple.
El HTML que se va a cargar se coloca en un
<div>
elemento para que tenga un contenedor que contiene todos los nodos que se van a cargar.Luego, este elemento contenedor se elimina del documento (pero el elemento DOME todavía existe).
Luego, se eliminan todos los hijos directos del documento. Esto incluye cualquier etiqueta agregada
<html>
,<head>
y<body>
(LIBXML_HTML_NOIMPLIED
opción efectiva ) así como la<!DOCTYPE html ... loose.dtd">
declaración (efectivaLIBXML_HTML_NODEFDTD
).Luego, todos los hijos directos del contenedor se agregan nuevamente al documento y se puede generar.
XPath funciona como de costumbre, solo tenga cuidado de que ahora haya varios elementos del documento, por lo que no un solo nodo raíz:
fuente
Ninguna de las otras soluciones en el momento de escribir este artículo (junio de 2012) pudo satisfacer completamente mis necesidades, así que escribí una que maneja los siguientes casos:
<doctype>
,<xml>
,<html>
,<body>
, y<p>
etiquetas)<p>
solo.Entonces, aquí hay una solución que soluciona esos problemas:
También escribí algunas pruebas que vivirían en esa misma clase:
Puedes comprobar que funciona por ti mismo.
DomDocumentWorkaround::testAll()
devuelve esto:fuente
De acuerdo, encontré una solución más elegante, pero es tediosa:
Muy bien, ¿con suerte esto no omite nada y ayuda a alguien?
fuente
Usa esta función
fuente
preg_replace
porque el uso de métodos basados en DOMDocument para eliminar las etiquetas html y body no conservaba la codificación UTF-8 :(Si la solución de banderas respondida por Alessandro Vendruscolo no funciona, puede intentar esto:
$bodyTag
contendrá su código HTML procesado completo sin todas esas envolturas HTML, excepto la<body>
etiqueta, que es la raíz de su contenido. Luego puede usar una expresión regular o una función de recorte para eliminarlo de la cadena final (despuéssaveHTML
) o, como en el caso anterior, iterar sobre todos sus hijos, guardar su contenido en una variable temporal$finalHtml
y devolverlo (lo que creo que es más seguro).fuente
Estoy luchando con esto en RHEL7 con PHP 5.6.25 y LibXML 2.9. (Cosas viejas en 2018, lo sé, pero eso es Red Hat para ti).
Descubrí que la solución sugerida por Alessandro Vendruscolo, muy votada, rompe el HTML al reorganizar las etiquetas. Es decir:
se convierte en:
Esto se aplica a las dos opciones que sugiere que uses:
LIBXML_HTML_NOIMPLIED
yLIBXML_HTML_NODEFDTD
.La solución sugerida por Alex va a mitad de camino para resolverlo, pero no funciona si
<body>
tiene más de un nodo hijo.La solución que me funciona es la siguiente:
Primero, para cargar DOMDocument, uso:
Para guardar el documento después de masajear el DOMDocument, uso:
Soy el primero en estar de acuerdo en que esta no es una solución muy elegante, pero funciona.
fuente
Agregar la
<meta>
etiqueta activará el comportamiento de reparación deDOMDocument
. Lo bueno es que no es necesario que agregue esa etiqueta en absoluto. Si no desea utilizar una codificación de su elección, simplemente páselo como un argumento de constructor.http://php.net/manual/en/domdocument.construct.php
Salida
Gracias a @Bart
fuente
Yo también tenía este requisito y me gustó la solución publicada por Alex arriba. Sin embargo, hay un par de problemas: si el
<body>
elemento contiene más de un elemento secundario, el documento resultante solo contendrá solo el primer elemento secundario de<body>
, no todos. Además, necesitaba la eliminación para manejar las cosas de manera condicional, solo cuando tenía un documento con los encabezados HTML. Así que lo refiné de la siguiente manera. En lugar de eliminarlo<body>
, lo transformé en a<div>
, y eliminé la declaración XML y<html>
.fuente
Al igual que otros miembros, primero me deleité con la simplicidad y el asombroso poder de la respuesta de @Alessandro Vendruscolo. La capacidad de simplemente pasar algunas constantes marcadas al constructor parecía demasiado buena para ser verdad. Para mi lo fue. Tengo las versiones correctas tanto de LibXML como de PHP, sin embargo, sin importar qué, todavía agregaría la etiqueta HTML a la estructura de nodo del objeto Document.
Mi solución funcionó mucho mejor que usar el ...
Banderas o ....
Eliminación de nodos, que se complica sin un orden estructurado en el DOM. Una vez más, los fragmentos de código no tienen forma de predeterminar la estructura DOM.
Comencé este viaje queriendo una forma simple de hacer un recorrido de DOM como lo hace JQuery o al menos de alguna manera que tuviera un conjunto de datos estructurados, ya sea un solo enlace, doblemente vinculado o un nodo transversal de árbol. No me importaba cuánto tiempo pudiera analizar una cadena de la forma en que lo hace HTML y también tener el increíble poder de las propiedades de la clase de entidad de nodo para usar en el camino.
Hasta ahora, DOMDocument Object me ha dejado con ganas ... Al igual que con muchos otros programadores, parece ... Sé que he visto mucha frustración en esta pregunta, así que desde FINALMENTE ... (después de aproximadamente 30 horas de intentar y fallar pruebas de tipo) He encontrado una manera de obtenerlo todo. Espero que esto ayude a alguien...
En primer lugar, soy cínico con TODO ... jajaja ...
Habría pasado toda la vida antes de estar de acuerdo con cualquier persona en que se necesita una clase de terceros en este caso de uso. Yo era y NO soy un fanático de usar ninguna estructura de clases de terceros, sin embargo, me encontré con un gran analizador. (unas 30 veces en Google antes de que me rindiera, así que no se sienta solo si lo evitó porque parecía poco oficial o poco oficial de alguna manera ...)
Si está utilizando fragmentos de código y necesita el código limpio y no se ve afectado por el analizador de ninguna manera, sin que se utilicen etiquetas adicionales, utilice simplePHPParser .
Es asombroso y se parece mucho a JQuery. No me impresiona a menudo, pero esta clase hace uso de muchas buenas herramientas y todavía no he tenido errores de análisis. Soy un gran admirador de poder hacer lo que hace esta clase.
Puede encontrar sus archivos para descargar aquí , sus instrucciones de inicio aquí y su API aquí . Recomiendo encarecidamente usar esta clase con sus métodos simples que pueden hacer de
.find(".className")
la misma manera que se usaría un método de búsqueda de JQuery o incluso métodos familiares comogetElementByTagName()
ogetElementById()
...Cuando guarda un árbol de nodos en esta clase, no agrega nada en absoluto. Simplemente puede decir
$doc->save();
y genera todo el árbol en una cadena sin ningún problema.Ahora usaré este analizador para todos los proyectos de ancho de banda sin límite en el futuro.
fuente
Tengo PHP 5.3 y las respuestas aquí no funcionaron para mí.
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
reemplacé todo el documento con solo el primer hijo, tenía muchos párrafos y solo se estaba guardando el primero, pero la solución me dio un buen punto de partida para escribir algo sinregex
dejar algunos comentarios y estoy bastante seguro de que esto se puede mejorar, pero si alguien tiene el mismo problema que yo, puede ser un buen punto de partida.Entonces podríamos usarlo así:
Tenga en cuenta que
appendChild
acepta unaDOMNode
para que no necesitemos crear nuevos elementos, simplemente podemos reutilizar los existentes que implementanDOMNode
, comoDOMElement
esto puede ser importante para mantener el código "sano" al manipular múltiples documentos HTML / XMLfuente
LIBXML_HTML_NOIMPLIED
ya que lo hace solo parcialmente. Eliminar el doctype es eficazLIBXML_HTML_NODEFDTD
.Me encontré con este tema para encontrar una manera de eliminar el contenedor HTML. Usar
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
funciona muy bien, pero tengo un problema con utf-8. Después de mucho esfuerzo encontré una solución. Lo publico a continuación para que cualquiera tenga el mismo problema.El problema causado por
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
El problema:
Solución 1:
Solución 2:
fuente
Me enfrento a 3 problemas con
DOMDocument
clase.1- Esta clase carga html con codificación ISO y caracteres utf-8 que no se muestran en la salida.
2- Incluso si damos
LIBXML_HTML_NOIMPLIED
bandera con el método loadHtml, hasta que nuestro HTML de entrada no contiene una etiqueta raíz, no será analizar correctamente.3- Esta clase considera inválidas las etiquetas HTML5.
Así que anulé esta clase para resolver estos problemas y cambié algunos de los métodos.
Ahora estoy usando en
DOMEditor
lugar deDOMDocument
y me ha funcionado bien hasta ahorafuente
También me encontré con este problema.
Desafortunadamente, no me sentí cómodo usando ninguna de las soluciones proporcionadas en este hilo, así que fui a ver una que me satisficiera.
Esto es lo que inventé y funciona sin problemas:
En esencia, funciona de manera similar a la mayoría de las soluciones proporcionadas aquí, pero en lugar de hacer trabajo manual, usa el selector xpath para seleccionar todos los elementos dentro del cuerpo y concatena su código html.
fuente
descendant-or-self::body/p/*
.mi servidor tiene php 5.3 y no se puede actualizar, así que esas opciones
no son para mi.
Para resolver esto, le digo a la función SaveXML que imprima el elemento Body y luego reemplace el "body" con "div"
aquí está mi código, espero que esté ayudando a alguien:
el utf-8 es para soporte en hebreo.
fuente
La respuesta de Alex es correcta, pero puede causar el siguiente error en los nodos vacíos:
Aquí viene mi pequeño mod:
Agregar el recorte () también es una buena idea para eliminar los espacios en blanco.
fuente
Quizás sea demasiado tarde. Pero tal vez alguien (como yo) todavía tenga este problema.
Entonces, nada de lo anterior funcionó para mí. Debido a que $ dom-> loadHTML también cierra etiquetas abiertas, no solo agrega etiquetas html y body.
Entonces, agregar un elemento <div> no me funciona, porque a veces tengo como 3-4 div sin cerrar en la pieza html.
Mi solución:
1.) Agregue marcador para cortar, luego cargue la pieza html
2.) haz lo que quieras con el documento
3.) guarda html
4.) antes de devolverlo, elimine las etiquetas <p> </ p> del marcador, curiosamente solo aparece en [MARK] pero no en [/ MARK] ...!?
5.) eliminar todo antes y después del marcador
6.) devuélvelo
Sería mucho más fácil si LIBXML_HTML_NOIMPLIED funcionara para mí. Debería, pero no lo es. PHP 5.4.17, libxml Versión 2.7.8.
Me parece realmente extraño, uso el analizador HTML DOM y luego, para arreglar esta "cosa", tengo que usar expresiones regulares ... El punto era, no usar expresiones regulares;)
fuente
< div >< div > ... < /div >
. Sigo buscando soluciones.Para cualquiera que use Drupal, hay una función incorporada para hacer esto:
https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x
Código de referencia:
fuente
Puede usar tidy con show-body-only:
Pero, recuerde: tidy elimine algunas etiquetas como Font Awesome icons: Problemas al sangrar HTML (5) con PHP
fuente
fuente
Esta biblioteca simplifica el recorrido / modificación del DOM y también se encarga de eliminar los envoltorios doctype / html por usted:
https://github.com/sunra/php-simple-html-dom-parser
fuente