Regex para colon em uma tag xml quando a análise falha com php e simplexml_load_string

Na sequência da minha última pergunta , se você tiver uma seqüência de caracteres que esteja malformada em um arquivo xml, você pode extrair o conteúdo usando preg_replace_callback () para remover os elementos que quebram.

O ponto desta function não é analisar o xml com regex (uma má idéia ), mas tentar encontrar o xml que não analisa e onde ele falha para que possamos marcar artigos que não estão sendo formatados corretamente antes de serem enviados Fora. Isso faz parte de um conjunto de ferramentas para limpar o conteúdo antes da entrega. Eu estou testando em URLs RSS malformadas conhecidas, bem como internas para ver se ela atende a uma série de situações. O retorno de chamada retornará um número inteiro para o nó que falhou. Se passar depois disso, podemos denunciar o índice do artigo e depois tentar usar o DOMDocument para tentar corrigir o html e tentar novamente. Se falhar, nós o denunciaremos como crítico, caso contrário, devolveremos a descrição e o conteúdo do artigo de análise ao database, marcando-o como modificado antes da entrega.

Você pode então tirar os elementos quebrados e executá-los através do DOMDocument para formatá-los melhor para retornar ao arquivo XML.

No entanto, estou preso a como tornar este exemplo abaixo o retorno diferente do falso:

XML de exemplo:

   

Se eu usar o seguinte PHP, posso extrair um nó de descrição e convertê-lo de:

  

para

 0 

PHP:

 preg_replace_callback( '/(.*)/', **// add msU modifiers to fix below** 'node_tidy::callback_description', $xml ); 

 private function callback_description($matches=false) { if(false !== $matches) { $this->arrDescriptions[] = $matches[1]; return ''.$this->indexDescriptions++.''; } else { return false; } } 

No entanto, quando tento fazer o mesmo com o content:encoded nós content:encoded , ele retorna falso. Aqui está a function relacionada:

 private function callback_content_encoded($matches=false) { if(false !== $matches) { $this->arrContentEncoded[] = $matches[1]; return ''.$this->indexContentEncoded++.''; } else { return false; } } 

Usando uma regex direta, para testar se é o cólon, usei isso:

 <?php $string = 'this is some text'; preg_match('/(.*)/',$string,$matches); echo '
'; print_r($matches); echo '

'; ?>

No entanto, isso não imprime a matriz esperada com ou sem adicionar \: Alguém poderia me apontar na direção certa para o mal entendido aqui?

Muito Obrigado!

UPDATE: Aqui está um fragment de amostra do xml real que falha, conforme indicado pelo @Florent.

http://pastebin.com/7z0f3MJP

UPDATE: este regex corresponde ao conteúdo desejado:

 preg_match('/(.*)/msU',$string,$matches); 

Os modificadores m e s e U são explicados melhor aqui: http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

Eu negligenciei considerar esses modificadores.

Os resultados agora são trazidos de volta por este regex, incluindo o problema original, então isso agora pode ser resolvido.

Você deve adicionar as seguintes bandeiras ao seu regex:

  • m para habilitar cordas multilinhas
  • u para habilitar as cordas UTF8 (se necessário)

O modificador multi-line não está sendo usado, então não é necessário. Somente o modificador / s (dot-all) é necessário. O modificador / U (não ganancioso) nunca deve ser usado (na minha opinião). O modificador / u (unicode) deve ser usado.

Se você estiver olhando para desinvestir o html dentro de uma estrutura CDATA, é melhor usar a especificação w3c para ele, ou seja, mesmo que seu xml use nomes de namespace para suas tags. Isso é somente se o único elemento na tag xml for um CDATA, e é assumido que o xml está bem formado.

No mundo real, os comentários podem envolver um CDATA e um visto-versa, além de esconder muitas outras coisas. Então, a realidade é que a regex pode analisar através do xml mal formado e depois recuperar, mas não é confiável e certamente é mais complicado.

Dito isto, isso extrairá o CDATA do seu exemplo e somente no seu sentido literal.

 if (preg_match( '~ \s* < !\[CDATA\[ (.*?) \]\]> \s* ~xsu', $string, $matches) ) { print ( $matches[1] ); }