我每天都需要编辑多个XML文件。我无法控制读取这些文件的源,也无法控制XML的格式。
问题是每个元素在每个块中都需要自己的序列号。有时每个块中可以有超过200个元素。当我需要在现有的长块中提前插入命令时,我必须手动重新编号每个后续元素,这些元素很乏味且容易出错。
此外,名称/值对与所需的顺序编号无关。下面的值“origcmd1”可能是“foobar98765”。它们的数量只是为了说明我的问题。
示例:
从这开始:
<block1>
<cmd1 name="origcmd1"></cmd1>
<cmd2 name="origcmd2">someCmdsTakeParams,param2</cmd2>
<cmd3 name="origcmd3"></cmd3>
</block1>
<block3> <c>no guarantee blocks are sequential #</c>
<cmd1 name="cmd1"></cmd1>
<cmd2 name="cmd2"></cmd2>
<cmd3 name="cmd3"></cmd3>
</block3>
如果我需要提前添加命令,请说origcmd1和origcmd2:
<block1>
<cmd1 name="origcmd1"></cmd1>
<cmd2 name="NEWcmd1"></cmd2> <c>cmd2 & cmd3 inserted</c>
<cmd3 name="NEWcmd1"></cmd3>
<cmd4 name="origcmd2">someCmdsTakeParams,param2</cmd4>
<cmd5 name="origcmd3"></cmd5>
</block1>
<block3> <c>no guarantee blocks are sequential #</c>
<cmd1 name="cmd1"></cmd1>
<cmd2 name="cmd2"></cmd2>
<cmd3 name="cmd3"></cmd3>
</block3>
我现在必须通过手动重新编号现在的cmd4和cmd5。当有数百个命令时,这会非常令人沮丧。
到目前为止,解决方案包括尝试编写宏以从第一行重新编号,假设它始终正确编号为1.然后我会使用一系列删除/粘贴和Ctrl-a来递增每个前进行数。不幸的是,我永远无法让宏工作正常。
我还查看了vim.org上的vim插件,但我发现没有任何我认为是解决方案。
Vim对我来说很新,但我喜欢它,这似乎是它非常适合解决的问题类型。对于我错过的快速技术或插件的任何想法都表示赞赏。
答案 0 :(得分:4)
以下似乎对我有用:
function! FixBlock()
let g:pos_end = search("<\/bloc")
call search("<block", "be")
let s:i = 0
while getpos(".")[1] < g:pos_end
call search("cmd", "e")
let s:i = s:i + 1
exe 's/^\(.*\)\(<cmd[^ ]*\) \(.*\)/\1cmd' . s:i . ' \3/'
"exe 's/^\(.*\)\(cmd.*\) \(.*\)/\1cmd' . s:i . ' \3/'
exe 's?\(.*\)\(</cmd.*\)>\(.*\)?\1</cmd' . s:i . '>\3'
normal j0
endwhile
endfunction
map ,fb :call FixBlock()
要使其工作,您应该在要修复的块内。 只需在正常模式下输入fb即可完成工作。
答案 1 :(得分:2)
如果XML的格式是相当固定的,你确实可以使用(有些复杂的)Vim宏来操作内容,但要注意XML格式的微妙变化(或注释掉的块)可能会造成严重破坏并破坏你的数据。由于Vim作为一般文本编辑器并没有真正理解XML结构,因此很难使宏更加健壮。
像 XSLT 这样的XML处理器可能更适合这项工作。 (虽然对我来说,在XSLT中编写转换比记录Vim宏更困难!但如果你经常需要它,那么它可能是值得的投资。)你甚至可以在Vim中调用它::%!xsltproc ...
< / p>
示例XSLT 1.0样式表...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(name(),'cmd')]">
<xsl:element name="cmd{position()}">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>