我正在尝试解析一个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
答案 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>
->匹配结束标记