6

私はこのようなデータを解析しようとしています:

<vin:layout name="Page" xmlns:vin="http://www.example.com/vin">
    <header>
        {someText}
        <div>
            <!-- some invalid xml code -->
            <aas>
            <nav class="main">
                <vin:show section="Menu" />
            </nav>
        </div>
    </header>
</vin:layout>

PHPでこのようなデータを解析するにはどうすればよいですか?

DOM を試しましたが、ルート要素内の xml の形式が正しくないため、機能しません。名前空間のないものはすべてテキストであることをパーサーに伝えることはできvinますか?

4

1 に答える 1

1

私はおそらくそれに一種の Tagsoup パーサーを投げるでしょう。その欠陥を除けば、あなたのフォーマットを読むことができる何かは、かなりうまく書かれているように見えます. 単純な正規表現ベースのスキャナーに対してテキスト的に邪魔になるものは何もありません。Tagsoup取得した 4 つのノード タイプ (開始タグ、終了タグ、テキスト、およびコメント) だけで私のものを呼び出しました。タグについては、タグ名と NamespacePrefix について知る必要があります。便宜上、XML/HTML に似た名前が付けられていますが、実際にはこれはすべて「独自のルール」であるため、これらの用語をいかなる標準にも拡張しないでください。

名前空間プレフィックスを持たないすべてのタグ (開始または終了) を変更する使用法は$string次のようになります (質問にあるデータが含まれています)。

$scanner = new TagsoupIterator($string);

$nsPrefix = 'vin';

foreach ($scanner as $node) {
    $isTag  = $node instanceof TagsoupTag;
    $isOfNs = $isTag && $node->getTagNsPrefix() === $nsPrefix;
    if ($isTag && !$isOfNs) {
        $node = strtr($node, ['&' => '&amp;', '<' => '&lt;']);
    }
    echo $node;
}

出力:

<vin:layout name="Page" xmlns:vin="http://www.example.com/vin">
    &lt;header>
        {someText}
        &lt;div>
            <!-- some invalid xml code -->
            &lt;aas>
            &lt;nav class="main">
                <vin:show section="Menu" />
            &lt;/nav>
        &lt;/div>
    &lt;/header>
</vin:layout>

名前空間の特定のタグ内のすべてを抽出する使用法は、次のようになります。

$scanner = new TagsoupIterator($string);
$parser  = new TagsoupForwardNavigator($scanner);

$startTagWithNsPrefix = function ($namespace) {

    return function (TagsoupNode $node) use ($namespace) {

        /* @var $node TagsoupTag */
        return $node->getType() === Tagsoup::NODETYPE_STARTTAG
            && $node->getTagNsPrefix() === $namespace;
    };
};

$start = $parser->nextCondition($startTagWithNsPrefix('vin'));
$tag   = $start->getTagName();
$parser->next();
echo $html = implode($parser->getUntilEndTag($tag));

出力:

<header>
    {someText}
    <div>
        <!-- some invalid xml code -->
        <aas>
        <nav class="main">
            <vin:show section="Menu" />
        </nav>
    </div>
</header>

次の部分は、 のその部分を置き換えること$stringです。Tagsoup はバイナリのオフセットと長さを提供するので、これは簡単です (そして、SimpleXML を介して少し汚れたショートカットを作成します):

$xml = substr($string, 0, $start->getEnd()) . substr($string, $parser->getOffset());
$doc = new SimpleXMLElement($xml);
$doc[0] = $html;
echo $doc->asXML();

出力:

<vin:layout xmlns:vin="http://www.example.com/vin" name="Page">
    &lt;header&gt;
        {someText}
        &lt;div&gt;
            &lt;!-- some invalid xml code --&gt;
            &lt;aas&gt;
            &lt;nav class="main"&gt;
                &lt;vin:show section="Menu" /&gt;
            &lt;/nav&gt;
        &lt;/div&gt;
    &lt;/header&gt;
</vin:layout>

具体的なニーズによっては、実装を変更する必要があります。たとえば、これは同じタグを互いに配置することを許可しません。それはあなたを捨てませんが、それを処理しません。その場合、開閉カウンターを追加する必要がある場合は、ナビゲーター クラスを簡単に拡張して、2 種類の終了タグ検索メソッドを提供することもできます。

ここに示す例は、次の要点で確認できる Tagsoup を使用しています: https://gist.github.com/4415105

于 2012-12-30T20:53:31.167 に答える