2012-12-07 68 views
5

我有多個需要每天編輯的XML文件。我無法控制讀取這些文件的源代碼,也無法控制XML的格式。Vim宏或插件按順序重新編號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

下,似乎爲我工作:

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,即可完成工作。

+0

謝謝,skeept。它幾乎可以工作,我正在圍繞着vimscript來理解發生了什麼。唯一的問題是當參數中有空格時。我很抱歉,我沒有指定這一點。我甚至沒有想到這可能是一個問題。 當空間是參數,可以這樣: ' ls -l命令,用grep -c老師' 變爲: '' 否則,一切似乎工作大大優於我之前有過。 (編輯時,如何在註釋中設置格式代碼) – Tye

+0

我修復了它以處理您的示例。讓我知道它是否適用於你知道的(我把舊行用'''留下了評論,所以你可以看到有什麼不同。「 – skeept

2

如果XML的格式是相當固定的,那麼確實可以使用(有點複雜的)Vim宏來操作內容,但要注意XML格式(或註釋掉的塊)中的細微變化可能會造成嚴重破壞你的數據。由於Vim作爲一般的文本編輯器沒有真正理解XML結構,因此很難使宏更加健壯。

這樣的XML處理器XSLT可能更適合這項工作。 (儘管對我來說,在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> 
+0

這是一個更好的方法。你介意我是否在你的答案中添加了XSLT示例?如果你願意的話,我可以添加我自己的答案。 –

+0

@DanielHaley:好的,繼續吧!用一個簡短的例子來說明這一點很好。 –