如何在PostgreSQL中移除HTML标签并保留指定例外标签?
1. 自定义strip_tags函数
先创建一个PL/pgSQL函数,通过"占位符替换"逻辑实现保留指定HTML标签、移除其余标签的效果——先保护允许的标签不被误删,再清除所有剩余标签,最后恢复允许的标签。
CREATE OR REPLACE FUNCTION strip_tags_keep_allowed(input_text text, allowed_tags text) RETURNS text AS $$ DECLARE tag_pattern text; placeholder_prefix text := '__TAG_HOLDER__'; placeholder_counter integer := 0; temp_text text := input_text; matched_tags text[]; current_tag text; BEGIN -- 自动为允许的标签添加对应的闭合标签(比如传入i会自动包含/i) allowed_tags := allowed_tags || ',' || replace(allowed_tags, ',', ',/'); -- 构建匹配允许标签的正则(支持带属性的标签,比如<p class="demo">) tag_pattern := '<(' || replace(allowed_tags, ',', '|') || ')([^>]*)>'; -- 第一步:将所有允许的标签替换为唯一占位符,避免被后续清除 WHILE temp_text ~ tag_pattern LOOP current_tag := substring(temp_text FROM tag_pattern); temp_text := regexp_replace(temp_text, tag_pattern, placeholder_prefix || placeholder_counter, 'g'); matched_tags[placeholder_counter] := current_tag; placeholder_counter := placeholder_counter + 1; END LOOP; -- 第二步:移除所有剩余的HTML标签 temp_text := regexp_replace(temp_text, '<[^>]*>', '', 'g'); -- 第三步:将占位符替换回原允许的标签 FOR i IN 0..array_length(matched_tags, 1)-1 LOOP temp_text := replace(temp_text, placeholder_prefix || i, matched_tags[i]); END LOOP; RETURN temp_text; END; $$ LANGUAGE plpgsql IMMUTABLE;
函数使用示例
-- 保留h1、p、strong、i标签,移除其他所有标签 SELECT strip_tags_keep_allowed( '<h1>测试标题</h1><p>这是<em>需要移除</em>的内容,<strong>加粗</strong>和<i>斜体</i>要保留,<script>alert("恶意脚本")</script>会被清除', 'h1,p,strong,i' );
执行后输出:
<h1>测试标题</h1><p>这是需要移除的内容,<strong>加粗</strong>和<i>斜体</i>要保留,会被清除
2. 用触发器自动处理字段
如果需要在插入/更新数据时自动清洗内容,可以创建触发器绑定上述函数。
假设你的表是content,包含raw_content(存储富文本原始内容)和clean_content(存储清洗后的内容)字段:
第一步:创建触发器函数
CREATE OR REPLACE FUNCTION clean_content_trigger() RETURNS TRIGGER AS $$ BEGIN -- 指定允许保留的标签,按需修改 NEW.clean_content := strip_tags_keep_allowed(NEW.raw_content, 'h1,p,strong,i'); RETURN NEW; END; $$ LANGUAGE plpgsql;
第二步:创建触发器
CREATE TRIGGER trigger_auto_clean_content BEFORE INSERT OR UPDATE ON content FOR EACH ROW EXECUTE FUNCTION clean_content_trigger();
之后每次插入或更新raw_content时,clean_content会自动生成清洗后的内容。
注意事项
- 该函数支持带属性的允许标签(比如
<p class="article">会被完整保留),如果需要仅保留无属性的标签,可以将正则修改为:tag_pattern := '<(' || replace(allowed_tags, ',', '|') || ')\s*>|<(' || replace(allowed_tags, ',', '|') || ')>'; - 正则处理HTML存在局限性,对于嵌套过深、不规范的HTML(比如未闭合标签)可能出现异常。如果需要更严谨的HTML解析,可以结合PostgreSQL的
xml类型进行处理(复杂度更高)。 - 函数标记为
IMMUTABLE,意味着相同输入会返回相同输出,适合用于索引或缓存优化。
内容的提问来源于stack exchange,提问作者Blumenthaler
相关产品推荐
相关产品推荐

