正则表达式PHP查找并匹配具有特定数据属性的HTML标签

时间:2018-11-09 11:26:38

标签: php regex

我正在尝试解析一个CTP文件(带有HTML和PHP标签的CakePHP模板),并希望将所有HTML标签与特定的数据属性(data-edit =“ true”)进行匹配。每个带有data-edit =“ true”的标记必须具有data-type =“ ...”和data-name =“ ...”属性。我想在(命名)组中捕获这些属性,因此可以在代码中使用它们。 到目前为止,我有以下正则表达式:

\<(?<tagname>\w+).*?(?>data\-edit="true").*?\>(?<content>.*?)\<\/(?&tagname)\>

以下是一些应该匹配的标签示例:

<h4 data-type="text" data-edit="true" data-name="SomeName">Some content, with or without newlines.</h4>

<span data-edit="true" data-type="wysiwyg" data-name="Beoordeling">Some text 
with <strong>tags</strong> and newlines in it that 
should not break the parser.</span>

在上面的示例中,我希望正则表达式返回data-type和data-name标签的内容,当然还包括标签之间的内容。

数据属性可以以任何顺序出现,并且标记中可能存在其他属性(例如类)。到目前为止,我已经设法只获取具有data-edit =“ true”属性的标签的内容,但是当有换行符时,匹配会中断。另外,我无法捕获其他数据属性。

我什至有可能实现?我知道regex不是解析HTML的首选方法,但是由于这是一个CTP文件,其中包含所有其他标记,因此我不能使用XML解析器。

编辑:示例代码:https://regex101.com/r/nF6a96/2

2 个答案:

答案 0 :(得分:1)

XPath是一款如此出色的多功能工具。您的逻辑无缝地转移到xpath查询,该查询将来很容易构造,读取和维护。

此外,XPath优于regex,因为无论属性的顺序如何,XPath都能成功匹配限定元素。正则表达式将很难通过一个preg_调用来做到这一点。

以下内容将循环验证,提取和存储仅一个查询的结果。

代码:(Demo

$dom=new DOMDocument; 
libxml_use_internal_errors(true);  // for malformed html warning suppression
$dom->loadHTML($text, LIBXML_NOENT);
//libxml_clear_errors();             // for  warning suppression
$xpath = new DOMXPath($dom);

foreach ($xpath->query("//*[@data-edit='true' and @data-type and @data-name]") as $node) {
    $results[] = [
                    'type' => $node->getAttribute('data-type'),
                    'name' => $node->getAttribute('data-name'),
                    'text' => $node->textContent
                 ];
}
var_export($results);

输出:

array (
  0 => 
  array (
    'type' => 'wysiwyg',
    'name' => 'Beoordeling',
    'text' => 'We beoordelen uw aanvraag en                                        berichten u over de acceptatie daarvan.',
  ),
  1 => 
  array (
    'type' => 'text',
    'name' => 'Bellen',
    'text' => 'We bellen u voor een afspraak.',
  ),
  2 => 
  array (
    'type' => 'text',
    'name' => 'Technisch specialist',
    'text' => 'Technisch specialist neemt bij u alles nog even door.',
  ),
)

答案 1 :(得分:0)

您应该避免使用正则表达式来解析html,但是由于这是在标签内进行属性查找的情况,而不是标签的某些嵌套情况,因此您可以在此处使用正则表达式进行快速验证。

您需要使用前瞻性来确保标记确实包含要查找的所有三种属性。您可以使用此正则表达式,

<(\w+)(?=.*?data-edit="true")(?=.*?data-type="[^"]*")(?=.*?data-name="[^"]*")[^>]*?>.*?<\/\1>

说明:

  • <(\w+)->匹配标签并捕获组1中的标签名以在结束标签的末尾进行匹配
  • (?=.*?data-edit="true")->先行并确保存在data-edit属性
  • (?=.*?data-type="[^"]*")->先行并确保存在数据类型属性
  • (?=.*?data-name="[^"]*")->先行并确保存在data-name属性
  • [^>]*?>->匹配其余的输入和结束标记
  • .*?->匹配开始和结束标记内的任何文本
  • <\/\1>->匹配结束标记

Demo