You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用xmlstarlet插入含引号、撇号并转义为实体的文本?

XML节点文本的引号与撇号转义需求

我写了一个bash脚本,要把文本输出到XML节点里。目前<、>、&已经能正常转义,但还想把引号(")和撇号(')也转成XML实体(&quot;、&apos;)。

操作示例及当前结果

$ inxi -S|tail -3
    Kernel: 5.19.16-100.fc35.x86_64
    arch: x86_64 bits: 64 Console: pty pts/1
    Distro: Fedora release 35 (Thirty Five)
 
$ xmlstarlet --version
compiled against libxml2 2.9.12, linked with 20914
compiled against libxslt 1.1.34, linked with 10135
 
$ printf '<foo>\n  <bar></bar>\n</foo>\n' | tee test.xml;
<foo>
  <bar></bar>
</foo>
 
$ xmlstarlet ed --inplace -u "//bar" -v "I'd like <this> text to be \"escaped\"." test.xml ; cat test.xml
<?xml version="1.0"?>
<foo>
  <bar>I'd like &lt;this&gt; text to be "escaped".</bar>                                          
</foo>
 
$ xmlstarlet ed --inplace -u "//bar" -v "I&amp;apos;d like <this> text to be &amp;quot;escaped&amp;quot;." test.xml ; cat test.xml                          
<?xml version="1.0"?>
<foo>
  <bar>I&amp;amp;apos;d like &lt;this&gt; text to be &amp;amp;quot;escaped&amp;amp;quot;.</bar>
</foo>

期望结果

<?xml version="1.0"?>
<foo>
  <bar>I&amp;apos;d like &lt;this&gt; text to be &amp;quot;escaped&amp;quot;.</bar>                                          
</foo>

请问能不能用xmlstarlet或者Fedora官方仓库里的其他XML工具实现这种转义效果?如果xmlstarlet不支持,是不是先按第一种方式插入文本,再用perl、sed等后处理是最优方案?


解决方案

一、xmlstarlet原生实现:自定义XSLT模板

xmlstarlet的ed命令默认只会强制转义<、>、&,不会自动处理引号和撇号。可以通过自定义XSLT模板实现完整实体转义:

  1. 创建escape.xsl模板文件:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="bar/text()">
    <xsl:call-template name="escape-xml">
      <xsl:with-param name="text" select="."/>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="escape-xml">
    <xsl:param name="text"/>
    <xsl:if test="$text != ''">
      <xsl:variable name="char" select="substring($text, 1, 1)"/>
      <xsl:choose>
        <xsl:when test="$char = '&amp;'">&amp;amp;</xsl:when>
        <xsl:when test="$char = '&lt;'">&amp;lt;</xsl:when>
        <xsl:when test="$char = '&gt;'">&amp;gt;</xsl:when>
        <xsl:when test="$char = '&quot;'">&amp;quot;</xsl:when>
        <xsl:when test="$char = '&apos;'">&amp;apos;</xsl:when>
        <xsl:otherwise><xsl:value-of select="$char"/></xsl:otherwise>
      </xsl:choose>
      <xsl:call-template name="escape-xml">
        <xsl:with-param name="text" select="substring($text, 2)"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>
  1. 执行插入+转义操作:
# 插入原始文本
xmlstarlet ed --inplace -u "//bar" -v "I'd like <this> text to be \"escaped\"." test.xml
# 应用XSLT完成全转义
xmlstarlet tr escape.xsl test.xml > test_escaped.xml && mv test_escaped.xml test.xml

二、后处理方案:perl高效转义(推荐)

如果觉得XSLT繁琐,先按常规方式插入文本,再用perl做后处理是最优选择——perl对正则和XML结构的兼容性更强,比sed更可靠:

# 插入未转义文本
xmlstarlet ed --inplace -u "//bar" -v "I'd like <this> text to be \"escaped\"." test.xml
# perl替换引号和撇号为XML实体
perl -pi -e 's/\'\''/&amp;apos;/g; s/"/&amp;quot;/g' test.xml

该命令会精准替换节点内的'为&apos;、"为&quot;,不会破坏已转义的&lt;、&gt;等实体。


内容的提问来源于stack exchange,提问作者zpangwin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 19:01:03