使用xmlstarlet将XML元素节点复制到另一个XML文件
问题描述
需要使用xmlstarlet工具,从一个XML文件中复制<keywords>和<authors>两个元素节点,到另一个已存在的XML文件的<from_old_xml>父节点下,最终<from_old_xml>仅包含这两个元素。
输入XML(input.xml)
<?xml version="1.0" encoding="utf-8"?> <article> <publication> <title locale="en_US">Ludo-Narrative Dissonance Revisited</title> <abstract locale="en_US"> which we see</abstract> <licenseUrl>https://creativecommons.org/licenses/by/4.0</licenseUrl> <copyrightHolder>Pawe;zyk, Bo Kampmann Walther</copyrightHolder> <copyrightYear>2023</copyrightYear> <keywords locale="en_US"> <keyword>Ludo-narrative dissonance</keyword> <keyword>ludology</keyword> </keywords> <authors xmlns:xsi="http://XMLSchema-instance"> <author include_in_browse="true"> <givenname locale="en_US">Pawe</givenname> <familyname locale="en_US">Grabarczyk</familyname> <affiliation locale="en_US">IT University</affiliation> </author> <author include_in_browse="true"> <givenname locale="en_US">Bo</givenname> <familyname locale="en_US">Kampmann Walther</familyname> <affiliation locale="en_US">University</affiliation> </author> </authors> </publication> </article>
目标XML(output.xml)格式
<?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> <journal-meta> <journal-id/> <journal-title-group/> <issn/> <journal-title-group/> <publisher> <publisher-name/> </publisher> </journal-meta> <article-meta> <article-id pub-id-type="doi">10.7557/23.6506</article-id> <title-group> <article-title>Game of Twisted Shouting</article-title> <subtitle>Ludo-Narrative Dissonance Revisited</subtitle> </title-group> <contrib-group/> </article-meta> <from_old_xml> <keywords> <keyword>Ludo-narrative dissonance</keyword> <keyword>ludology</keyword> <keyword>narrativity</keyword> <keyword>gameplay</keyword> <keyword>games and violence</keyword> </keywords> <authors> <author> <givenname>Bo</givenname> <familyname>Kampmann Walther</familyname> </author> <author> <givenname>Bo</givenname> <familyname>Kampmann Walther</familyname> </author> </authors> </from_old_xml> </front> </article>
失败的命令
xmlstarlet ed -L \ -s "//article/front" -t test -n "from_old_xml" -v "$(xmlstarlet select --omit-decl -t --copy-of '//article/publication/keywords' input.xml)" output.xml
解决方案
你的命令存在三个核心问题:
- 创建节点的类型参数错误,应该用
-t elem而非-t test - 直接将XML片段作为
-v的值会触发语法解析错误,无法正确处理嵌入标签 - 未处理
<authors>节点的复制,也没控制<from_old_xml>的内容范围
步骤1:确保<from_old_xml>节点存在
如果目标文件output.xml中还没有该节点,先执行创建命令:
xmlstarlet ed -L \ -s "//article/front" -t elem -n from_old_xml \ output.xml
步骤2:复制<keywords>和<authors>节点
通过管道操作避免XML片段转义问题,分别复制两个节点到<from_old_xml>下:
# 复制keywords节点 xmlstarlet select --omit-decl -t --copy-of '//article/publication/keywords' input.xml | \ xmlstarlet ed -L \ -s "//article/front/from_old_xml" -t elem -n temp -v - \ -u "//article/front/from_old_xml/temp" -x "." \ output.xml # 复制authors节点 xmlstarlet select --omit-decl -t --copy-of '//article/publication/authors' input.xml | \ xmlstarlet ed -L \ -s "//article/front/from_old_xml" -t elem -n temp -v - \ -u "//article/front/from_old_xml/temp" -x "." \ output.xml
可选:清空<from_old_xml>原有内容
如果目标节点已有其他内容,需要先清空再插入:
xmlstarlet ed -L \ -d "//article/front/from_old_xml/*" \ output.xml
执行完这条命令后,再运行步骤2的复制命令即可。
操作说明
- 管道操作用于规避命令行传递XML片段的转义问题
-u "//temp" -x "."的作用是展开临时节点的内容,将复制的XML节点直接转为<from_old_xml>的子节点-L参数会直接修改目标文件,若想预览结果可去掉该参数,输出到终端查看
内容的提问来源于stack exchange,提问作者Ofuuzo
相关产品推荐
相关产品推荐

