Sou a função abaixo, estou lutando para gerar o DOMDocument sem anexar os wrappers de tag XML, HTML, body e p antes da saída do conteúdo. A correção sugerida:
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
Só funciona quando o conteúdo não tem elementos de nível de bloco dentro dele. No entanto, quando isso acontece, como no exemplo abaixo com o elemento h1, a saída resultante de saveXML é truncada para ...
<p> Se você gosta </p>
Eu fui apontado para esta postagem como uma possível solução alternativa, mas não consigo entender como implementá-la nesta solução (consulte as tentativas comentadas abaixo).
Alguma sugestão?
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;
}
fonte
DOMDocument
que também afeta o código nesta resposta. Afaik,DOMDocument
sempre interpreta os dados de entrada como latin-1 , a menos que a entrada especifique um conjunto de caracteres diferente . Em outras palavras: a<meta charset="…">
tag parece ser necessária para dados de entrada que não sejam latin-1. Caso contrário, a saída será interrompida para, por exemplo, caracteres UTF-8 multibyte.Basta remover os nós diretamente após carregar o documento com loadHTML ():
fonte
<!DOCTYPE
funciona. A segunda linha é quebrada se<body>
tiver mais de uma nota filha.Em
saveXML()
vez disso, use e passe documentElement como um argumento para ele.http://php.net/domdocument.savexml
fonte
saveHTML
bem ( exemplo )loadHTML
libxml usa o módulo analisador HTML e isso irá inserir o esqueleto HTML ausente. Conseqüentemente,$dom->documentElement
será o elemento HTML raiz. Eu consertei seu código de exemplo. Agora deve fazer o que Scott está pedindo.O problema com a resposta principal é que ela
LIBXML_HTML_NOIMPLIED
é instável .Ele pode reordenar os elementos (particularmente, movendo a tag de fechamento do elemento superior para a parte inferior do documento), adicionar
p
tags aleatórias e talvez uma variedade de outros problemas [1] . Pode remover ohtml
ebody
tags para você, mas ao custo de um comportamento instável. Na produção, é uma bandeira vermelha. Em resumo:Não use
LIBXML_HTML_NOIMPLIED
. Em vez disso, usesubstr
.Pense nisso. Os comprimentos de
<html><body>
e</body></html>
são fixos e em ambas as extremidades do documento - seus tamanhos nunca mudam e nem suas posições. Isso nos permite usarsubstr
para cortá-los:( ESTA NÃO É A SOLUÇÃO FINAL NO ENTANTO! Veja abaixo a resposta completa , continue lendo para o contexto)
Cortamos
12
desde o início do documento porque<html><body>
= 12 caracteres (<<>>+html+body
= 4 + 4 + 4), e voltamos e cortamos 15 no final porque\n</body></html>
= 15 caracteres (\n+//+<<>>+body+html
= 1 + 2 + 4 + 4 + 4)Observe que eu ainda uso
LIBXML_HTML_NODEFDTD
omitir!DOCTYPE
de ser incluído. Primeiro, isso simplifica asubstr
remoção das tags HTML / BODY. Segundo, não removemos o doctype comsubstr
porque não sabemos se o 'default doctype
' sempre terá um comprimento fixo. Mas mais importante,LIBXML_HTML_NODEFDTD
impede o analisador DOM de aplicar um doctype não HTML5 ao documento - o que pelo menos evita que o analisador trate os elementos que não reconhece como texto solto.Sabemos com certeza que as tags HTML / BODY têm comprimentos e posições fixas, e sabemos que constantes como
LIBXML_HTML_NODEFDTD
nunca são removidas sem algum tipo de aviso de depreciação, então o método acima deve rolar bem no futuro, MAS ...... a única ressalva é que a implementação do DOM pode mudar a maneira como as tags HTML / BODY são colocadas no documento - por exemplo, removendo a nova linha no final do documento, adicionando espaços entre as tags ou adicionando novas linhas.
Isso pode ser remediado pesquisando as posições das tags de abertura e fechamento
body
e usando esses deslocamentos como para nossos comprimentos para aparar. Usamosstrpos
estrrpos
para encontrar os deslocamentos da frente e de trás, respectivamente:Para encerrar, uma repetição da resposta final, preparada para o futuro :
Sem doctype, sem tag html, sem tag body. Podemos apenas esperar que o analisador DOM receba uma nova camada de tinta em breve e possamos eliminar mais diretamente essas tags indesejadas.
fonte
$html = $dom -> saveHTML();
vez de$dom -> saveHTML();
repetidamente?Um truque bacana é usar
loadXML
e entãosaveHTML
. As tagshtml
ebody
são inseridas noload
palco, não nosave
palco.Observe que isso é um pouco hacky e você deve usar a resposta de Jonah se puder fazer funcionar.
fonte
use DOMDocumentFragment
fonte
É 2017 e, para esta questão de 2011, não gosto de nenhuma das respostas. Muitos regex, grandes classes, loadXML etc ...
Solução fácil que resolve os problemas conhecidos:
Fácil, simples, sólido, rápido. Este código funcionará em relação a tags HTML e codificação como:
Se alguém encontrar um erro, diga, eu mesmo usarei.
Editar , Outras opções válidas que funcionam sem erros (muito semelhantes às já fornecidas):
Você mesmo poderia adicionar corpo para prevenir qualquer coisa estranha no furure.
Trinta opção:
fonte
mb_convert_encoding
e, em vez disso, adicionando<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>
e modificando desubstr
acordo. Aliás, a sua solução é a mais elegante aqui. Votos positivos.Estou um pouco atrasado no clube, mas não queria deixar de compartilhar um método que descobri. Em primeiro lugar, tenho as versões certas de loadHTML () para aceitar essas opções legais, mas
LIBXML_HTML_NOIMPLIED
não funcionou no meu sistema. Também os usuários relatam problemas com o analisador (por exemplo, aqui e aqui ).A solução que criei é bem simples.
O HTML a ser carregado é colocado em um
<div>
elemento para que tenha um contêiner contendo todos os nós a serem carregados.Em seguida, esse elemento de contêiner é removido do documento (mas o DOMElement dele ainda existe).
Em seguida, todos os filhos diretos do documento são removidos. Isto inclui qualquer adicionado
<html>
,<head>
e<body>
tags (efetivamenteLIBXML_HTML_NOIMPLIED
opção), bem como a<!DOCTYPE html ... loose.dtd">
declaração (efetivamenteLIBXML_HTML_NODEFDTD
).Em seguida, todos os filhos diretos do contêiner são adicionados ao documento novamente e ele pode ser gerado.
XPath funciona normalmente, apenas tome cuidado para que haja vários elementos de documento agora, portanto, não um único nó raiz:
fonte
Nenhuma das outras soluções até o momento em que este livro foi escrito (junho de 2012) foi capaz de atender completamente às minhas necessidades, então escrevi uma que lida com os seguintes casos:
<doctype>
,<xml>
,<html>
,<body>
, e<p>
etiquetas)<p>
sozinho.Portanto, aqui está uma solução que corrige esses problemas:
Também escrevi alguns testes que viveriam nessa mesma classe:
Você pode verificar se funciona sozinho.
DomDocumentWorkaround::testAll()
retorna este:fonte
Ok, encontrei uma solução mais elegante, mas é entediante:
Tudo bem, espero que isso não omita nada e ajude alguém?
fonte
Use esta função
fonte
preg_replace
porque usar métodos baseados em DOMDocument para remover as tags html e body não estavam preservando a codificação UTF-8 :(Se a solução de sinalizadores respondida por Alessandro Vendruscolo não funcionar, você pode tentar o seguinte:
$bodyTag
conterá seu código HTML totalmente processado sem todos os envoltórios de HTML, exceto para a<body>
tag, que é a raiz do seu conteúdo. Então você pode usar um regex ou uma função trim para removê-lo da string final (depoissaveHTML
) ou, como no caso acima, iterar sobre todos os seus filhos, salvando seu conteúdo em uma variável temporária$finalHtml
e retornando-o (o que eu acredito ser mais seguro).fonte
Estou lutando com isso no RHEL7 executando PHP 5.6.25 e LibXML 2.9. (Coisas antigas em 2018, eu sei, mas isso é Red Hat para você.)
Eu descobri que a solução muito votada sugerida por Alessandro Vendruscolo quebra o HTML ao reorganizar as tags. Ie:
torna-se:
Isso vale para ambas as opções que ele sugere que você use:
LIBXML_HTML_NOIMPLIED
eLIBXML_HTML_NODEFDTD
.A solução sugerida por Alex vai no meio do caminho para resolvê-lo, mas não funciona se
<body>
tiver mais de um nó filho.A solução que funciona para mim é a seguinte:
Primeiro, para carregar o DOMDocument, eu uso:
Para salvar o documento depois de massagear o DOMDocument, eu uso:
Sou o primeiro a concordar que esta não é uma solução muito elegante - mas funciona.
fonte
Adicionar a
<meta>
tag irá desencadear o comportamento de fixação deDOMDocument
. A parte boa é que você não precisa adicionar essa tag. Se você não quiser usar uma codificação de sua escolha, passe-a como um argumento do construtor.http://php.net/manual/en/domdocument.construct.php
Resultado
Obrigado a @Bart
fonte
Eu também tinha esse requisito e gostei da solução postada por Alex acima. No entanto, há alguns problemas - se o
<body>
elemento contiver mais de um elemento filho, o documento resultante conterá apenas o primeiro elemento filho de<body>
, não todos eles. Além disso, eu precisava da remoção para lidar com as coisas condicionalmente - somente quando você tinha um documento com os cabeçalhos HTML. Então, eu o refinei da seguinte maneira. Em vez de removê-lo<body>
, transformei-o em um<div>
e retirei a declaração XML e<html>
.fonte
Assim como outros membros, eu primeiro me deliciei com a simplicidade e o incrível poder da resposta de @Alessandro Vendruscolo. A capacidade de simplesmente passar algumas constantes sinalizadas para o construtor parecia boa demais para ser verdade. Para mim foi. Eu tenho as versões corretas de LibXML e também de PHP, no entanto, não importa o que, ele ainda adicionaria a tag HTML à estrutura de nó do objeto Document.
Minha solução funcionou muito melhor do que usar o ...
Sinalizadores ou ....
Remoção de nó, que fica confusa sem uma ordem estruturada no DOM. Novamente, os fragmentos de código não têm como predeterminar a estrutura do DOM.
Comecei esta jornada querendo uma maneira simples de fazer a travessia do DOM como o JQuery faz ou pelo menos de alguma forma que tivesse um conjunto de dados estruturados tanto com link único, quanto com link duplo ou travessia de nó em árvore. Eu não me importava por quanto tempo eu poderia analisar uma string como o HTML e também ter o poder incrível das propriedades da classe de entidade de nó para usar ao longo do caminho.
Até agora, o Objeto DOMDocument me deixou com desejos ... Como muitos outros programadores, parece ... Eu sei que tenho visto muita frustração nesta questão, então, desde que FINALMENTE ... (após cerca de 30 horas de tentativas e fracassos teste de tipo) Eu encontrei uma maneira de conseguir tudo. Espero que isso ajude alguém...
Em primeiro lugar, sou cínico de TUDO ... rs ...
Eu teria passado uma vida inteira antes de concordar com alguém que uma classe de terceiros é de qualquer maneira necessária neste caso de uso. Eu era e NÃO sou um fã de usar qualquer estrutura de classe de terceiros, mas me deparei com um ótimo analisador. (cerca de 30 vezes no Google antes de eu ceder, então não se sinta sozinho se você evitou, porque parecia coxo ou não oficial de alguma forma ...)
Se você estiver usando fragmentos de código e precisar do, código limpo e não afetado pelo analisador de nenhuma forma, sem tags extras sendo usadas, use simplePHPParser .
É incrível e funciona muito como JQuery. Não fico impressionado com frequência, mas esta classe usa várias ferramentas boas e ainda não tive erros de análise. Eu sou um grande fã de ser capaz de fazer o que esta classe faz.
Você pode encontrar seus arquivos para download aqui , suas instruções de inicialização aqui e sua API aqui . Eu recomendo fortemente o uso desta classe com seus métodos simples que podem fazer
.find(".className")
da mesma maneira que um método find JQuery seria usado ou até mesmo métodos familiares comogetElementByTagName()
ougetElementById()
...Quando você salva uma árvore de nós nesta classe, ela não adiciona nada. Você pode simplesmente dizer
$doc->save();
e ele produz a árvore inteira em uma string sem qualquer problema.Agora irei usar este analisador para todos os projetos de largura de banda sem limite no futuro.
fonte
Tenho PHP 5.3 e as respostas aqui não funcionaram para mim.
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
substituí todo o documento com apenas o primeiro filho, eu tinha muitos parágrafos e apenas o primeiro estava sendo salvo, mas a solução me deu um bom ponto de partida para escrever algo semregex
deixar alguns comentários e tenho certeza que isso pode ser melhorado, mas se alguém tem o mesmo problema que eu, pode ser um bom ponto de partida.Então, poderíamos usá-lo assim:
Observe que
appendChild
aceita um,DOMNode
portanto, não precisamos criar novos elementos, podemos apenas reutilizar os existentes que implementamDOMNode
comoDOMElement
este pode ser importante para manter o código "são" ao manipular vários documentos HTML / XMLfonte
LIBXML_HTML_NOIMPLIED
já que o faz apenas parcialmente. Remover o doctype é eficazLIBXML_HTML_NODEFDTD
.Me deparei com este tópico para encontrar uma maneira de remover o wrapper HTML. Usar
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
funciona muito bem, mas tenho um problema com o utf-8. Depois de muito esforço, encontrei uma solução. Posto abaixo para quem tiver o mesmo problema.O problema causado por causa de
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
O problema:
Solução 1:
Solução 2:
fonte
Eu enfrento 3 problemas com as
DOMDocument
aulas.1- Essa classe carrega html com codificação ISO e caracteres utf-8 não exibidos na saída.
2 Mesmo se dermos
LIBXML_HTML_NOIMPLIED
bandeira para o método loadHTML, até o nosso html de entrada não contém uma tag raiz, não será analisado corretamente.3- Esta classe considera as tags HTML5 inválidas.
Portanto, substituí esta classe para resolver esses problemas e alterei alguns dos métodos.
Agora estou usando em
DOMEditor
vez deDOMDocument
e tem funcionado bem para mim até agorafonte
Também me deparei com esse problema.
Infelizmente, não me senti confortável em usar nenhuma das soluções fornecidas neste tópico, então fui verificar uma que me satisfizesse.
Aqui está o que eu criei e funciona sem problemas:
Em essência, ele funciona de maneira semelhante à maioria das soluções fornecidas aqui, mas em vez de fazer trabalho manual, ele usa o seletor xpath para selecionar todos os elementos dentro do corpo e concatena seu código html.
fonte
descendant-or-self::body/p/*
.meu servidor tem php 5.3 e não pode atualizar essas opções
não são para mim.
Para resolver isso, digo à função SaveXML para imprimir o elemento Body e, em seguida, apenas substituir o "corpo" por "div"
aqui está meu código, espero que esteja ajudando alguém:
o utf-8 é para suporte em hebraico.
fonte
A resposta de Alex está correta, mas pode causar o seguinte erro em nós vazios:
Aí vem meu pequeno mod:
Adicionar o trim () também é uma boa ideia para remover os espaços em branco.
fonte
Talvez seja tarde demais. Mas talvez alguém (como eu) ainda tenha esse problema.
Portanto, nenhuma das opções acima funcionou para mim. Porque $ dom-> loadHTML também fecha as tags abertas, não apenas adiciona as tags html e body.
Portanto, adicionar um elemento <div> não está funcionando para mim, porque às vezes tenho 3-4 div não fechado na parte html.
Minha solução:
1.) Adicione um marcador para cortar e, em seguida, carregue a peça html
2.) faça o que quiser com o documento
3.) salve o html
4.) antes de devolvê-lo, remova as tags <p> </ p> do marcador, estranhamente ele só aparece em [MARK], mas não em [/ MARK] ...!?
5.) remova tudo antes e depois do marcador
6.) devolvê-lo
Seria muito mais fácil se LIBXML_HTML_NOIMPLIED funcionasse para mim. Schould, mas não é. PHP 5.4.17, libxml Versão 2.7.8.
Eu acho muito estranho, eu uso o analisador HTML DOM e então, para consertar essa "coisa" eu tenho que usar regex ... A questão toda era, não usar regex;)
fonte
< div >< div > ... < /div >
. Ainda estou procurando soluções.Para qualquer pessoa que use o Drupal, há uma função integrada para fazer isso:
https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x
Código para referência:
fonte
Você pode usar tidy com show-body-only:
Mas, lembre-se: remova cuidadosamente algumas tags como Ícones impressionantes de fonte: Problemas de recuo HTML (5) com PHP
fonte
fonte
Esta biblioteca simplifica a passagem / modificação do DOM e também se encarrega de remover os wrappers doctype / html para você:
https://github.com/sunra/php-simple-html-dom-parser
fonte