Pergunta

Eu tenho vários documentos legados semelhantes a HTML.Tipo, eles se parecem com HTML, mas têm tags adicionais inventadas que não fazem parte do HTML

<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>

Eu preciso analisar esses arquivos.PHP é a única ferramenta disponível.Os documentos não chegam nem perto de serem XML bem formados.

Meu pensamento original era usar os métodos loadHTML em PHPs DOMDocument.No entanto, esses métodos engasgam com as tags HTML compostas e se recusam a analisar a string/arquivo.

$oDom = new DomDocument();
$oDom->loadHTML("<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>");
//gives us
DOMDocument::loadHTML() [function.loadHTML]: Tag pseud-template invalid in Entity, line: 1 occured in ....

A única solução que consegui encontrar é pré-processar os arquivos com funções de substituição de string que removerão as tags inválidas e as substituirão por uma tag HTML válida (talvez um span com um id do nome da tag).

Existe uma solução mais elegante?Uma maneira de informar o DOMDocument sobre tags adicionais a serem consideradas válidas?Existe uma classe/objeto de análise HTML diferente e robusto para PHP?

(se não for óbvio, não considero expressões regulares uma solução válida aqui)

Atualizar:As informações nas tags falsas fazem parte do objetivo aqui, então algo como o Tidy não é uma opção.Além disso, estou atrás de algo que faça algum nível, senão todo, de limpeza de boa formação para mim, e é por isso que eu estava procurando o método loadHTML do DomDocument em primeiro lugar.

Foi útil?

Solução

Você pode suprimir avisos com libxml_use_internal_errors, ao carregar o documento.Por exemplo.:

libxml_use_internal_errors(true);
$doc = new DomDocument();
$doc->loadHTML("<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>");
libxml_use_internal_errors(false);

Se, por algum motivo, você precisar acessar os avisos, use libxml_get_errors

Outras dicas

Eu me pergunto se passar o HTML "ruim" HTML arrumado pode ajudar como uma primeira passagem?Pode valer a pena dar uma olhada, se você conseguir que o documento fique bem formado, talvez você possa carregá-lo como um arquivo XML normal com DomDocument.

@Twan Você não precisa de um DTD para DomDocument para analisar XML personalizado.Apenas use DOMDocument->load(), e desde que o XML esteja bem formado, ele poderá lê-lo.

Depois de fazer com que os arquivos estejam bem formados, você poderá começar a examinar os analisadores XML, antes disso você estará S.O.L.Lok Alejo disse, você poderia olhar HTML ARRUMADO, mas parece que isso é específico do HTML e não sei como seria com seus elementos personalizados.

Não considero expressões regulares uma solução válida aqui

Até que você esteja bem formado, essa pode ser sua única opção.Depois de levar os documentos a esse estágio, você estará limpo com as funções do DOM.

Dê uma olhada no Parser na porta PHP Fit.O código é limpo e foi originalmente projetado para carregar o HTML sujo salvo pelo Word.Está configurado para extrair tabelas, mas pode ser facilmente adaptado.

Você pode ver a fonte aqui:http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/Parser.phps

O teste de unidade mostrará como usá-lo:http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/test/parser.phps

Minha solução rápida e suja para esse problema foi executar um loop que correspondesse à minha lista de tags personalizadas com uma expressão regular.O regexp não captura tags que possuem outra tag personalizada interna dentro delas.

Quando há uma correspondência, uma função para processar aquela tag é chamada e retorna o "HTML processado".Se essa tag personalizada estiver dentro de outra tag personalizada, o pai não terá filhos pelo fato de o HTML real ter sido inserido no lugar do filho, e será correspondido pelo regexp e processado na próxima iteração do loop.

O loop termina quando não há tags personalizadas sem filhos a serem correspondidas.No geral, é iterativo (um loop while) e não recursivo.

@Alan Tempestade

Seu comentário sobre minha outra resposta me fez pensar:

Quando você carrega um arquivo HTML com DOMDocument, parece que ele faz algum nível de limpeza:bem formado, MAS exige que todas as suas tags sejam tags HTML legítimas.Estou procurando algo que faça o primeiro, mas não o último.(Alan Tempestade)

Execute uma regex (desculpe!) sobre as tags e, quando encontrar uma que não seja um elemento HTML válido, substitua-a por um elemento válido que você sabe que não existe em nenhum dos documentos (blink vem à mente...), e atribua a ele um valor de atributo com o nome do elemento ilegal, para que você possa alterá-lo novamente depois.por exemplo:

$code = str_replace("<pseudo-tag>", "<blink rel=\"pseudo-tag\">", $code);
// and then back again...
$code = preg_replace('<blink rel="(.*?)">', '<\1>', $code);

obviamente esse código não funcionará, mas você entendeu?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top