私はおそらくそれに一種の 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, ['&' => '&', '<' => '<']);
}
echo $node;
}
出力:
<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>
名前空間の特定のタグ内のすべてを抽出する使用法は、次のようになります。
$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">
<header>
{someText}
<div>
<!-- some invalid xml code -->
<aas>
<nav class="main">
<vin:show section="Menu" />
</nav>
</div>
</header>
</vin:layout>
具体的なニーズによっては、実装を変更する必要があります。たとえば、これは同じタグを互いに配置することを許可しません。それはあなたを捨てませんが、それを処理しません。その場合、開閉カウンターを追加する必要がある場合は、ナビゲーター クラスを簡単に拡張して、2 種類の終了タグ検索メソッドを提供することもできます。
ここに示す例は、次の要点で確認できる Tagsoup を使用しています: https://gist.github.com/4415105