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

使用xmlstarlet合并XML后,如何对导入元素执行unescape处理

问题:XML节点插入后被转义,如何转为正常节点

我有两个XML文件A和B,希望将A中的特定元素节点插入到B中。操作执行成功,但导入的元素在B中被转义(显示为<这类实体),需要处理成正常的XML节点结构。

XML文件A

<?xml version="1.0"?>
<article>
  <publication>
     <authors>
      <author>
        <givenname locale="en_US">Admin</givenname>
        <givenname locale="nb_NO">Admin</givenname>
        <familyname locale="en_US">Septentrio</familyname>
        <email>septentrio@ub.uit.no</email>
      </author>
      <author include_in_browse="true" user_group_ref="Forfatter" seq="0" id="13075">
        <givenname locale="nb_NO">Peter</givenname>
        <familyname locale="nb_NO">Nilsen</familyname>
        <affiliation locale="nb_NO">NTL University</affiliation>
        <country>NO</country>
        <email>ofuuzo@gmail.com</email>
      </author>
    </authors>
  </publication>
</article>

XML文件B

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.2 20190208//EN" "JATS-archivearticle1.dtd">
<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.2" article-type="other">
  <front>
  </front>
</article>

原执行命令

xmlstarlet ed -L -s "//article/front" -t elem -n "newchild"  -v "$(xmlstarlet  sel  --omit-decl  -t -c "/article/publication/authors/author" a.xml)" b.xml

得到的结果(节点被转义)

<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.2 20190208//EN" "JATS-archivearticle1.dtd">
<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.2" article-type="other">
  <front>
  <newchild>&lt;author&gt;
        &lt;givenname locale="en_US"&gt;Admin&lt;/givenname&gt;
        &lt;givenname locale="nb_NO"&gt;Admin&lt;/givenname&gt;
        &lt;familyname locale="en_US"&gt;Septentrio&lt;/familyname&gt;
        &lt;email&gt;septentrio@ub.uit.no&lt;/email&gt;
        &lt;/author&gt;&lt;author include_in_browse="true" user_group_ref="Forfatter" seq="0" id="13075"&gt;
        &lt;givenname locale="nb_NO"&gt;Peter&lt;/givenname&gt;
        &lt;familyname locale="nb_NO"&gt;Nilsen&lt;/familyname&gt;
        &lt;affiliation locale="nb_NO"&gt;NTL University&lt;/affiliation&gt;
        &lt;country&gt;NO&lt;/country&gt;
        &lt;email&gt;ofuuzo@gmail.com&lt;/email&gt;
      &lt;/author&gt;</newchild></front>
</article>

解决方法

原因分析

原命令使用-v参数将选中的XML内容作为文本字符串赋值给新节点,XML解析器会自动将<、>等特殊字符转义为实体(&lt;、&gt;)。要直接插入XML节点结构,需操作节点而非文本。

方案1:使用XMLStarlet的sel命令直接合并节点

通过document()函数读取外部XML文件的节点,直接插入目标位置:

xmlstarlet sel -t \
  -c "/article" \
  --insert "/article/front" \
  -t -c "document('a.xml')/article/publication/authors/author" \
  b.xml > output.xml

如果需要直接修改B文件,可添加-L参数(注意:直接修改原文件前建议备份):

xmlstarlet sel -L -t \
  -c "/article" \
  --insert "/article/front" \
  -t -c "document('a.xml')/article/publication/authors/author" \
  b.xml

方案2:使用XSLT转换

创建XSLT文件(如merge_authors.xsl),定义节点合并逻辑:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 引入外部XML文件A -->
  <xsl:param name="authors-source" select="document('a.xml')"/>

  <!-- 复制所有原有节点 -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- 在front节点下插入A中的author节点 -->
  <xsl:template match="//article/front">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <xsl:copy-of select="$authors-source/article/publication/authors/author"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

执行转换命令:

xmlstarlet tr merge_authors.xsl b.xml > output.xml
# 直接修改原文件:
xmlstarlet tr -L merge_authors.xsl b.xml

最终效果

执行后B文件的front节点下会直接插入正常的author节点,而非转义后的文本:

<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.2 20190208//EN" "JATS-archivearticle1.dtd">
<article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" dtd-version="1.2" article-type="other">
  <front>
    <author>
      <givenname locale="en_US">Admin</givenname>
      <givenname locale="nb_NO">Admin</givenname>
      <familyname locale="en_US">Septentrio</familyname>
      <email>septentrio@ub.uit.no</email>
    </author>
    <author include_in_browse="true" user_group_ref="Forfatter" seq="0" id="13075">
      <givenname locale="nb_NO">Peter</givenname>
      <familyname locale="nb_NO">Nilsen</familyname>
      <affiliation locale="nb_NO">NTL University</affiliation>
      <country>NO</country>
      <email>ofuuzo@gmail.com</email>
    </author>
  </front>
</article>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:37:00