5

我有多个需要每天编辑的 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 对我来说是新的,但我喜欢它,这似乎是它非常适合解决的问题类型。任何关于我错过的快速技术或插件的想法都值得赞赏。

4

2 回答 2

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 就可以了。

于 2012-12-07T05:40:57.253 回答
2

如果 XML 的格式相当固定,您确实可以使用(有些复杂的)Vim 宏来操作内容,但要注意 XML 格式的细微变化(或注释掉的块)可能会造成严重破坏并破坏您的数据。由于 Vim 作为通用文本编辑器对 XML 结构没有真正的了解,因此很难使宏更加健壮。

像XSLT这样的 XML 处理器可能更适合这项工作。(虽然对我来说,在 XSLT 中编写转换比录制 Vim 宏更难!但如果你经常需要它,它可能是值得的投资。)你甚至可以在 Vim 中调用它::%!xsltproc ...

示例 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>
于 2012-12-07T07:51:07.997 回答