查看一些用于 XML 和 HTML 的 Perl 解析器,如上面 Miller 回答所指出的 Mojo::DOM 以及 XML::TreePP,我发现他们正在使用正则表达式来解析整个内容,所以我尝试了他们的正则表达式和得到了很好的结果,只是可能需要一些优化。
这是我所做的:
my $text =<<'XHTML';
some text
<p>hello p</p>
<vars type="text" name= "fname" single='single quoted' unqouted=noquotes hastags=" <b>color='red'</b> Class::SubClass->color"/>
other text or html open tags like
<vars type="text" name= "lname" single1='single quoted' unqouted1=noquotes hastags1=" <b>bgcolor='red'</b> Class::SubClass->bgcolor">
<table><tr>
<vars name="mname" />
XHTML
while ( $text =~ m{(<vars\s+([^\!\?\s<>](?:"[^"]*"|'[^']*'|[^"'<>\/])*)/?>)}sxgi ) {
my $match = $1;
my $args = $2;
#print "[[$match]] \n{{$args}}\n\n";
#parse name=value attributes, values may be double or single quoted or unquoted
while ( $args =~ m/([^<>=\s\/]+|\/)(?:\s*=\s*(?:"([^"]*?)"|'([^']*?)'|([^>\s\/]*)))?\s*/sxgi ) {
my $name = $1;
#any better solution with regex above to just get $2
my $value = $2? $2: ($3? $3 : $4);
print "$name=$value\n";
}
print "\n";
}
这是预期的输出:
type=text
name=fname
single=single quoted
unqouted=noquotes
hastags= <b>color='red'</b> Class::SubClass->color
type=text
name=lname
single1=single quoted
unqouted1=noquotes
hastags1= <b>bgcolor='red'</b> Class::SubClass->bgcolor
name=mname
当然,代码中的变量 $match 具有整个匹配项,因此我可以将其替换为我的内容。
匹配属性的第二个正则表达式需要优化,我对这一行不满意:
my $value = $2? $2: ($3? $3 : $4);
是否可以修改正则表达式以仅获取 $2 中的属性值。
Mojo::Dom 中使用的正则表达式是
my $ATTR_RE = qr/
([^<>=\s\/]+|\/) # Key
(?:
\s*=\s*
(?:
"([^"]*?)" # Quotation marks
|
'([^']*?)' # Apostrophes
|
([^>\s\/]*) # Unquoted
)
)?
\s*
/x;
my $END_RE = qr!^\s*/\s*(.+)!;
my $TOKEN_RE = qr/
([^<]+)? # Text
(?:
<\?(.*?)\?> # Processing Instruction
|
<!--(.*?)--\s*> # Comment
|
<!\[CDATA\[(.*?)\]\]> # CDATA
|
<!DOCTYPE(
\s+\w+
(?:(?:\s+\w+)?(?:\s+(?:"[^"]*"|'[^']*'))+)? # External ID
(?:\s+\[.+?\])? # Int Subset
\s*
)>
|
<(
\s*
[^<>\s]+ # Tag
\s*
(?:$ATTR_RE)* # Attributes
)>
|
(<) # Runaway "<"
)??
/xis;
我只是弄乱了它来匹配是否带有或不带有斜杠 > 或 /> 的结束标记。