PHP:仅解析命名空间的xml

dko*_*och 6 php xml parsing dom

我正在尝试解析这样的数据:

<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>
Run Code Online (Sandbox Code Playgroud)

如何在PHP中解析这样的数据?

我尝试了DOM,但它不起作用,因为根元素中的格式错误的xml.我可以告诉解析器,没有vin命名空间的ifithing 是文本吗?

hak*_*kre 1

我可能会在上面添加一种 Tagsoup 解析器。可以读取您的格式的东西,除了这些缺陷之外,看起来写得还不错。任何文本内容都不会妨碍基于简单正则表达式的扫描器。我Tagsoup只用你得到的四种节点类型来调用我的:Starttag、Endtag、Text 和 Comment。对于标签,您需要了解其标签名和命名空间前缀。只是为了方便起见,它的命名类似于 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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

<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>
Run Code Online (Sandbox Code Playgroud)

提取命名空间的某个标记内的所有内容的用法可能如下所示:

$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));
Run Code Online (Sandbox Code Playgroud)

输出:

<header>
    {someText}
    <div>
        <!-- some invalid xml code -->
        <aas>
        <nav class="main">
            <vin:show section="Menu" />
        </nav>
    </div>
</header>
Run Code Online (Sandbox Code Playgroud)

下一部分是替换$string. 由于 Tagsoup 提供了二进制偏移量和长度,这很容易(我通过 SimpleXML 的快捷方式有点脏):

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

输出:

<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>
Run Code Online (Sandbox Code Playgroud)

根据具体需求,这需要改变实施方式。例如,这个不允许将相同的标签放入彼此中。它不会把你赶出去,但它不会处理这个问题。不知道您是否有这种情况,如果是这样,您需要添加一些打开/关闭计数器,导航器类可以轻松扩展,甚至可以提供两种结束标记查找方法。

此处给出的示例使用 Tagsoup,您可以在以下要点中看到: https: //gist.github.com/4415105