0

私の最後の質問のフォローアップで、xml ファイルに不正な形式の文字列がある場合、preg_replace_callback() を使用してコンテンツを抽出し、破損した要素を削除できます。

この関数のポイントは、xml を regex で解析することではなく (悪い考えです)、解析できない xml と解析に失敗した場所を見つけて、送信前に正しくフォーマットされていない記事にフラグを立てることができるようにすることです。アウト。これは、配信前にコンテンツをクリーニングする一連のツールの一部です。既知の不正な公開 RSS URL と内部 URL でテストして、さまざまな状況に対応できるかどうかを確認しています。コールバックは、失敗したノードの整数を返します。その後合格した場合は、記事のインデックスを報告し、DOMDocument を使用して html を修正し、再試行することができます。失敗した場合は重大として報告します。それ以外の場合は、解析中の記事の説明とコンテンツをデータベースに戻し、配信前に変更済みとしてマークします。

次に、壊れた要素を取得して DOMDocument で実行し、より適切にフォーマットして XML ファイルに戻すことができます。

ただし、以下の例で false 以外を返す方法に行き詰まっています。

サンプル XML:

<item>
    <content:encoded><![CDATA[
        This is the text with odd characters that are killing 
        simplexml_load_string() (doesn't recover) and breaking 
        (although recoverable) DOMDocument
    ]]></content:encoded>
</item>

次の PHP を使用すると、説明ノードを抽出して変換できます。

<description><![CDATA[
    This is some description text with the same problem
]]></description>

<description>0</description>

PHP:

preg_replace_callback(
    '/<description>(.*)<\/description>/', **// 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 '<description>'.$this->indexDescriptions++.'</description>';
    } else {
        return false;
    }
}

ただし、ノードで同じことをしようとすると、content:encodedfalse が返されます。関連する関数は次のとおりです。

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

ストレート正規表現を使用して、それがコロンかどうかをテストするために、これを使用しました:

<?php

$string = '<content:encoded>this is some text</content:encoded>';
preg_match('/<content\:encoded>(.*)<\/content\:encoded>/',$string,$matches);

echo '<pre>';
print_r($matches);
echo '</pre>';

?>

ただし、追加の有無にかかわらず、期待される配列を出力しませんでした\:。ここでの誤解について、誰かが私を正しい方向に向けることができますか?

どうもありがとう!

更新: @Florent で示されているように、失敗した実際の xml のサンプル スニペットを次に示します。

http://pastebin.com/7z0f3MJP

更新: この正規表現は、必要なコンテンツと一致します。

preg_match('/<content\:encoded>(.*)<\/content\:encoded>/msU',$string,$matches);

m および s および U 修飾子については、こちらで詳しく説明しています: http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

これらの修飾子を考慮することを怠っていました。

元の問題を含め、この正規表現によって結果が返されるようになったため、これを解決できるようになりました。

4

2 に答える 2

1

次のフラグを正規表現に追加する必要があります。

  • m複数行の文字列を有効にする
  • uUTF8 文字列を有効にする (必要な場合)
于 2012-07-09T16:01:44.767 に答える
0

複数行修飾子は使用されていないため、必要ありません。/s (すべてドット) 修飾子のみが必要です。/U (貪欲でない) 修飾子は (私の意見では) 使用しないでください。/u (ユニコード) 修飾子を使用する必要があります。

CDATA 構造内で html をラップ解除する場合は、xml がそのタグに名前空間名を使用していても、w3c 仕様、つまり を使用することをお勧めします。これは、xml タグ内の唯一の要素が CDATA であり、xml が整形式であると想定されている場合のみです。

現実の世界では、コメントは CDATA をラップしたり、その逆を行ったり、他の多くのものを隠したりすることができます。したがって、現実には、正規表現は不正な形式の xml を解析してから回復できる可能性がありますが、信頼性が低く、確かにより複雑です。

そうは言っても、これはあなたの例から文字通りの意味でのみ CDATA を抽出します。

if (preg_match(
   '~<content:encoded\s*>
       \s*
       <!\[CDATA\[ (.*?) \]\]>
       \s*
     </content:encoded\s*>~xsu',
    $string,
    $matches) )
{
 print ( $matches[1] );
}
于 2012-07-09T18:17:05.613 に答える