使用 lorem.dita 作为示例 XML 文档,通过正则表达式提取出该文档中的所有 XML 标签,并转换为简单的 XSLT 样式表。可以在 Github 中找到 lorem.dita 文件,地址是https://github.com/michaeljamesfitzgerald/Introducing-Regular-Expressions。为了节省篇幅,节选部分文本作为测试数据。
drop table if exists t1;
create table t1 (a text);
insert into t1 values
('<?xml version="1.0" encoding="UTF-8"?>
<!PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">
<topic id="lorem">
<title>Lorem Ipsum</title>
<body>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras non commodo mi. </p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit:</p>
<ul>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
<li>Lorem ipsum dolor sit amet</li>
</ul>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. </p>
</body>
</topic>'
);
with
t1 as -- 提取、去重、排序所有标签
(
with recursive num as
(select n, regexp_substr(a,'<[_a-zA-Z][^>]*>',1,t.n) b from t1,(select 1 n) t
union all
select n+1, regexp_substr(a,'<[_a-zA-Z][^>]*>',1, n + 1) from t1, num
where b is not null)
select replace(convert(group_concat(distinct b order by b) using utf8mb4),',',char(10)) a from num),
t2 as -- 替换掉标签属性
(select regexp_replace(a,' id=".*"','') a from t1),
t3 as -- 给标签添加常量字符串
(select regexp_replace(a,'^<(.*)>$','<xsl:template match="$1">
<xsl:apply-templates/>
</xsl:template>
',1,0,'m') a from t2),
t4 as -- 添加头尾字符串
(select regexp_replace(a,'^(.*)$','<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\n\n$1\n</xsl:stylesheet>',1,0,'n') a from t3)
select * from t4;
查询结果如下:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="body">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="li">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="p">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="title">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="topic">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="ul">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
该实现使用内嵌视图、递归查询技术,并调用 regexp_substr 和 regexp_replace 函数完成标签的提取和替换。
<[_a-zA-Z][^>]*>
with recursive num as
(select n, regexp_substr(a,'<[_a-zA-Z][^>]*>',1,t.n) b from t1,(select 1 n) t
union all
select n+1, regexp_substr(a,'<[_a-zA-Z][^>]*>',1, n + 1) from t1, num
where b is not null)
MySQL 的 regexp_substr 函数用于返回正则表达式的匹配项,但每次只能返回一个,用第四个参数 occurrence 指定返回第几个匹配项。为了获得全部标签,需要使用递归查询,将递归变量作为 occurrence 参数传递给 regexp_substr 函数。将 regexp_substr 函数返回 null 作为递归退出条件。这部分查询为每个标签返回一行。
select replace(convert(group_concat(distinct b order by b) using utf8mb4),',',char(10)) a from num
内嵌视图 t1 的查询结果即为 去重、排序后的,以换行符作为分隔符的所有标签。
select regexp_replace(a,' id=".*"','') a from t1
内嵌视图 t2 的查询结果为去掉属性的所有标签名称。本例中只有 id 属性。
select regexp_replace(a,'^<(.*)>$','<xsl:template match="$1">
<xsl:apply-templates/>
</xsl:template>
',1,0,'m') a from t2
内嵌视图 t3 的查询结果是个每个标签添加了带有 XSLT 样式的前后缀。使用多行模式后,正则表达式 ^<(.*)>
select regexp_replace(a,'^(.*)$','<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\n\n$1\n</xsl:stylesheet>',1,0,'n') a from t3
内嵌视图 t4 的查询结果是给 t3 的结果添加首尾 XSLT 标签字符串。使用 dotall 模式后,正则表达式 ^(.*) 匹配整个多行文本,并将匹配结果放入一个捕获组中,1 引用该捕获组。