使用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><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></newchild></front> </article>
解决方法
原因分析
原命令使用-v参数将选中的XML内容作为文本字符串赋值给新节点,XML解析器会自动将<、>等特殊字符转义为实体(<、>)。要直接插入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
相关产品推荐
相关产品推荐

