我有很多 xml 文件。我需要根据tag1="alpha"
xml 中的特定标签(例如 )重命名每个标签。
我已经弄清楚如何根据单身的特定标签的出现。
find . -maxdepth 1 -name '*.xml' -exec /rename.sh {} \;
#!/bin/bash
tag1=$(sed 's/.*tag1="\([^"]*\).*/\1/; q' "$1")
mv -v "$1" "$tag1.xml"
问题:有些文件有多个tag1
标签,例如tag1="alpha"
tag1="beta"
tag1="omega"
.对于这些文件,我还需要创建同一文件的副本,但使用其他名称,beta.xml
, omega.xml
。
我尝试使用位置参数进行cat,但这不起作用(我是初学者)。
文件结构示例:
<root xmlns:d="http://www.apple.com/DTDs/DictionaryService-1.0.rng">
<div class="div-entry"><d:entry xmlns:d="1.0.rng" id="m_en_gbus0240000" tag1="cudgel" class="entry">
<span class="hg x_xh0">
<span role="text" d:syl="1" class="hw">cudg.el<d:syl/></span>
<span prxid="cudgel_us_nv" prlexid="pron0014256.002" dialect="AmE" class="prx"> | <span d:prn="US" dialect="AmE" class="ph t_respell">ˈ;ke;je;l<d:prn/></span><span d:prn="IPA" soundFile="cudgel#_us_1" media="online" dialect="AmE" class="ph">ˈ;ke;dʒe;l<d:prn/></span> | </span>
</span>
<span class="sg">
<span id="m_en_gbus0240000.004" class="se1 x_xd0">
<span role="text" class="posg x_xdh">
<span d:pos="1" class="pos">
<span class="gp tg_pos">noun </span>
<d:pos/>
</span>
</span>
<span id="m_en_gbus0240000.005" class="msDict x_xd1 t_core">
<span d:def="1" role="text" class="df">a short, thick stick used as a weapon<span class="gp tg_df">. </span><d:def/></span>
</span>
<span class="gp x_xdt tg_se1"> </span>
</span>
<span id="m_en_gbus0240000.008" class="se1 x_xd0">
<span class="x_xdh">
<span role="text" class="posg">
<span d:pos="2" class="pos">
<span class="gp tg_pos">verb </span>
<d:pos/>
</span>
<span class="infg"><span class="gp tg_infg">(</span><span tag1="cudgels", <span tag1="cudgeling"<span class="pr"/>, <span tag1="cudgeled"<span class="pr"/>; <span class="lg"><span class="ge">British </span></span><span tag1="cudgels", <span tag1="cudgelling", <span tag1="cudgelled"<span class="gp tg_infg">) </span></span>
</span>
<span role="text" class="gg"><span class="gp tg_gg">[</span>with <span class="sy">object</span><span class="gp tg_gg">] </span></span>
</span>
<span id="m_en_gbus0240000.011" class="msDict x_xd1 t_core">
<span d:def="2" role="text" class="df">beat with a cudgel<d:def/></span>
<span role="text" class="gp tg_df">: </span>
<span role="text" class="eg">
<span class="ex"> they would lie in wait and cudgel her to death</span>
<span class="gp tg_eg">. </span>
</span>
</span>
</span>
<span class="gp tg_sg"> </span>
</span>
<span class="subEntryBlock x_xo0 t_phrases">
<span class="gp x_xoLblBlk ty_label tg_subEntryBlock">PHRASES </span>
<span id="m_en_gbus0240000.022" class="subEntry x_xo1">
<span class="x_xoh">
<span role="text" tag1="cudgel one's brains "
<span class="vg"><span class="gp tg_vg">(</span>also <span id="m_en_gbus0240000.037" tag1="cudgel one's brain"<span class="gp tg_vg">) </span></span>
</span>
<span id="m_en_gbus0240000.024" class="msDict x_xo2 t_core">
<span role="text" class="lg">
<span class="ge">British </span>
</span>
<span role="text" class="df">think hard about a problem</span>
<span role="text" class="gp tg_df">: </span>
<span role="text" class="eg">
<span class="ex"> she cudgeled her brains, trying to decide what had caused such an about-face</span>
<span class="gp tg_eg">. </span>
</span>
</span>
<span class="gp x_xot tg_subEntry"> </span>
</span>
<span id="m_en_gbus0240000.025" class="subEntry x_xo1">
<span role="text" tag1="take up the cudgels "
<span id="m_en_gbus0240000.026" class="msDict x_xo2 t_core">
<span role="text" class="df">start to defend or support someone or something strongly</span>
<span role="text" class="gp tg_df">: </span>
<span role="text" class="eg">
<span class="ex"> there was no one else to take up the cudgels on their behalf</span>
<span class="gp tg_eg">. </span>
</span>
</span>
</span>
</span>
<span role="text" class="etym x_xo0">
<span class="gp x_xoLblBlk ty_label tg_etym">ORIGIN </span>
<span class="x_xo1"><span class="dg"><span class="date">Old English </span></span><span class="italic">cycgel</span>, of unknown origin<span class="gp tg_etym">.</span></span>
</span>
</d:entry>
<div class="div-entry"><div>
</root>
答案1
为什么不使用xmlstarlet
提取
tag1
短语并在 shell 脚本循环中处理其输出。
xmlstarlet select
接受多个路径名作为输入,因此可以与s{} +
的更有效变体一起使用find
-exec
操作数。请注意,-exec … {} +
始终评估为 true,因此它不会在非零退出状态下中止。要列出文件名以及
tag1
转换后的短语,例如:
# shellcheck shell=sh disable=SC2016
find . -maxdepth 3 -type f -name '*.xml' -exec \
xmlstarlet select --text -t \
--var tag1nodes='//@tag1[name(..)="span" or name(..)="div"]' \
--var allowchars -o 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' -b \
--var tag1cvt -o 'translate(normalize-space(),translate(.,$allowchars,""),"_")' -b \
-m 'set:distinct(dyn:map($tag1nodes,$tag1cvt))' \
-s 'A:T:-' '.' \
-f -o "${ofs:-$(printf '\t')}" -v '.' -n \
{} +
xmlstarlet select
命令注释
select
使用第一个输入文件的根元素中的命名空间定义(并预定义xsl
、saxon
和来自 EXSLT 的命名空间),引用的任何其他命名空间都必须使用-N
选项定义- 变量从或元素
tag1nodes
收集tag1
短语(属性值),此处div
span
假定位于默认命名空间或空同上 - EXSLT
dyn:map
tag1cvt
函数通过评估参数(以文本字符串形式给出的 XPath 表达式) 将每个短语映射到字符串,其中 - EXSLT 的
set:distinct
消除重复 - 排序顺序为:
A
升序、T
扩展、未指定大小写顺序 tag1
如果未找到相关值,则不会生成任何输出(在这种情况下select
返回 1)-C
之前添加一个选项-t
将列出 XSLT 1.0 样式表select
使用- 添加此处的定义
--var
是为了提高可读性,并可以轻松地替换为dyn:map
参数 - 路径名
find
来自假定没有'
(单引号)字符,由于已知错误 在select
- 空格,如果处理输出的 shell 脚本使用默认
IFS
值read
部分样本输出:
./dir-b/fum.xml cudgels
./dir-b/fum.xml take_up_the_cudgels
./fee.xml cudgel_ones_brain
./fee.xml cudgel_ones_brains
./fee.xml cudgeled
./fee.xml cudgeling
./fee.xml cudgelled
./fee.xml cudgelling
您发布的文件不是 XML,但xmlstarlet
可以恢复其内容(省略-q
列出错误):
xmlstarlet -q format -R junk > file.xml
答案2
这个问题似乎有两个独立的部分。第一个是查找所有 tag1 出现的内容。第二部分是如何使用它们来重命名您的 xml 文件。从当前帖子来看,第二部分的条件尚不完全清楚。
这只是第一部分的解决方案。
$ sed 's/tag1/\ntag1/g' input_file | sed -n '/tag1/p' | cut -d '"' -f2
cudgel
cudgels
cudgeling
cudgeled
cudgels
cudgelling
cudgelled
cudgel one's brains
cudgel one's brain
take up the cudgels