当后代元素与祖先具有相同名称时,删除特定元素内的所有元素

时间:2015-07-08 09:23:06

标签: php xml xpath

我正在使用PHP,我想删除特定标记内的所有标记并仅保留纯文本。我坚持的问题是,有一些子标签与父标签的名称相同:

<corpo>
    <num>1.</num>
    <mod id="mod167">
        String 1
        <commas id="mod167-vir1" type="word">String 2</commas>
        <com id="mod166-vir1-20090024-art13-com16.1"><num>&lt;&lt;16.</num></com>
        <rif xlink:href="urn" xlink:type="simple">String 3</rif><h:p>Something here</h:p>
        <corpo>String 4</corpo>
   </mod>
</corpo>

例如,corpo具有同名的子标记(<corpo>String 4</corpo>),num标记使用了两次(<num>1.</num>和{{1} }})在父标记<num>&lt;&lt;16.</num>内。

从最高corpo标记开始,我想删除每个子标记并仅保留纯文本。结果应该是:

corpo

到目前为止,我尝试使用SimpleXML和PHP <corpo> String 1 String 2 &lt;&lt;16. String 3 Something here String 4 </corpo> 添加了我想要保留的所有标记,但当然它没有给出我期望的结果。

strip_tags

2 个答案:

答案 0 :(得分:1)

如果将XML加载到DOM中,则可以阅读DOMNode::$textContent属性。

$document = new DOMDocument();
$document->loadXml($xml);

var_dump($document->documentElement->textContent);

输出包含文本内容,包括所有空格。

string(113) "
    1.

        String 1
        String 2
        <<16.
        String 3Something here
        String 4

"

在更复杂的结构中,使用Xpath获取值。函数normalize-space()将第一个节点强制转换为字符串,删除前导和尾随空格,并将所有其他空白组转换为单个空格。

$xpath = new DOMXpath($document);
var_dump($xpath->evaluate('normalize-space(/corpo)'));

输出:

string(58) "1. String 1 String 2 <<16. String 3Something here String 4"

要创建包含已删除标记的XML,请导入不带子项的corpo节点并附加文本内容:

$target = new DOMDocument();
foreach ($xpath->evaluate('/corpo') as $corpo) {
  $target
    ->appendChild(
      $target->importNode($corpo)
    )->appendChild(
      $target->createTextNode(
        $xpath->evaluate('normalize-space(.)', $corpo)
      )
    );
}

echo $target->saveXml();

输出:

<?xml version="1.0"?>
<corpo xmlns:xlink="urn:xlink" xmlns:h="urn:h">1. String 1 String 2 &lt;&lt;16. String 3Something here String 4</corpo>

答案 1 :(得分:1)

  

这与@ThW编写的内容非常相关,更侧重于SimpleXML。我还在xpath上显示了一些不同的角度来选择公司元素。

如果文档中的字符$buffer与字符$xml = simplexml_load_string($buffer); foreach ($xml->xpath('//corpo[not(ancestor::corpo)]') as $corpo) { $corpo[0] = dom_import_simplexml($corpo)->textContent; } $xml->asXML('php://output'); 相同或更多,那么这是一个XML示例:

<a xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h="ns:h">
    <b>
        <corpo>
            1.

                String 1
                String 2

                    &lt;&lt;16.

                String 3
                Something here
                String 4

        </corpo>
    </b>
</a>

其示例性输出是:

//corpo[not(ancestor::corpo)]

它的工作原理如下:

获取每个 corpo 元素,该元素没有具有该名称的祖先。这是由xpath:

完成的
$corpo

然后,因为这是一个 SimpleXMLElement ,并且您想要文本内容,可以通过dom_import_simplexml($corpo)->textContent; 关联的 DOMElement 节点访问它:

$corpo[0] = ...

剩下的表达

strip_tags($corpo->asXML())

告诉您更新 SimpleXMLElement 的内容(所谓的自引用)。

BTW你可以在这里使用dom_import_simplexml($corpo)->textContent代替strip_tags,但我不会建议,因为我不知道preg_replace到底有多稳定。它至少不符合XML标准。

现在你可能也想要应用一些空格规范化,因为foreach ($xml->xpath('//corpo[not(ancestor::corpo)]') as $corpo) { $text = dom_import_simplexml($corpo)->textContent; $corpo[0] = preg_replace('~\s+~u', ' ', $text); } 对于UTF-8标志很方便,这是 SimpleXMLElement DOMElement使用的字符串编码

<?xml version="1.0"?>
<a xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h="ns:h">
    <b>
        <corpo> 1. String 1 String 2 &lt;&lt;16. String 3 Something here String 4 </corpo>
    </b>
</a>

此变体为您提供:

<?php

$buffer = <<<XML
<a xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h="ns:h">
    <b>
        <corpo>
            <num>1.</num>
            <mod id="mod167">
                String 1
                <commas id="mod167-vir1" type="word">String 2</commas>
                <com id="mod166-vir1-20090024-art13-com16.1">
                    <num>&lt;&lt;16.</num>
                </com>
                <rif xlink:href="urn" xlink:type="simple">String 3</rif>
                <h:p>Something here</h:p>
                <corpo>String 4</corpo>
            </mod>
        </corpo>
    </b>
</a>
XML;


$xml = simplexml_load_string($buffer);

foreach ($xml->xpath('//corpo[not(ancestor::corpo)]') as $corpo) {
    $text     = dom_import_simplexml($corpo)->textContent;
    $corpo[0] = preg_replace('~\s+~u', ' ', $text);
}

$xml->asXML('php://output');

完整示例一览Demo

WITH myCTE AS
(
Your Query here!!!
)
SELECT *, furtherData
FROM myCTE