2012-12-07 8 views
5

Mam wiele plików XML, które muszę codziennie edytować. Nie mam kontroli nad źródłem, które odczytuje te pliki i nie ma kontroli nad formatem XML.Vim makro lub wtyczka do sekwencyjnego ponumerowania elementów xml?

Problem polega na tym, że każdy element wymaga własnego numeru sekwencyjnego w każdym bloku. Czasami w każdym bloku może znajdować się ponad 200 elementów. Kiedy muszę wstawić polecenie wcześnie w istniejącym długim bloku, muszę ręcznie przenumerować każdy kolejny element, który jest uciążliwy i podatny na błędy.

Ponadto pary nazwa/wartość nie mają połączenia z konieczną kolejną numeracją. Wartość "origcmd1" poniżej mogła być "foobar98765". Są one tylko po to, by zilustrować mój problem.

Przykład:

Wychodząc z tego:

<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> 

Jeśli muszę dodać polecenie wcześnie, powiedzmy między origcmd1 i 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> 

muszę teraz przejść i ręcznie przenumeruj co teraz są cmd4 i cmd5. Kiedy są setki poleceń, staje się to bardzo frustrujące.

Do tej pory rozwiązania obejmowały próbę napisania makra do numeracji od pierwszego wiersza, zakładając, że jest ono zawsze poprawnie numerowane jako 1. Następnie używałbym serii kasowań/wklejek, a Ctrl-a by zwiększał każde postępowanie. numer kolejki. Niestety, nigdy nie mogłem uzyskać poprawnego działania makra.

Przeglądałem także vim plugins na vim.org, ale nie znalazłem niczego, co rozpoznałbym jako rozwiązanie.

Vim jest dla mnie nowy, ale podoba mi się to i wydaje się, że jest to rodzaj problemu, który dobrze nadaje się do rozwiązania. Wszelkie pomysły na szybką technikę lub plugin, które przeoczyłem, są doceniane.

Odpowiedz

4

Poniższa wydaje się działać dla mnie:

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() 

go do pracy, trzeba być w środku bloku, który chcesz naprawić. Po prostu wpisz, fb w trybie mormal i to powinno działać.

+0

Dziękuję, skeept. To * prawie * działa i pakuję głowę w vimscript, aby zrozumieć, co się dzieje. Jedynym problemem jest to, kiedy parametry zawierają spacje. Przepraszam, że tego nie sprecyzowałem.Nawet nie przyszło mi do głowy, że to może być problem. Kiedy przestrzenie są w params, to: ' ls -l, grep -c nauczyciela' staje: '' przeciwnym razie wszystko wydaje się działać znacznie lepiej niż to, co ja miał wcześniej. (edytowane, gdy zastanawiam się, jak sformatować kod w komentarzach) – Tye

+0

Naprawiłem to, aby obsłużyć twój przykład. Daj mi znać, jeśli to działa, bo wiesz (zostawiłem starą linię skomentowaną przez '' ', abyś mógł zobaczyć jaka jest różnica – skeept

2

Jeśli formatowanie XML jest raczej ustalone, można rzeczywiście użyć (nieco skomplikowanych) makr Vima do manipulowania treścią, ale należy pamiętać, że subtelne zmiany w formatowaniu XML (lub skomentowane bloki) mogą siać spustoszenie i korupcję Twoje dane. Ponieważ Vim jako ogólny edytor tekstu nie ma prawdziwego zrozumienia struktury XML, trudno jest uczynić makro bardziej niezawodnym.

Procesor XML, taki jak XSLT może być lepiej przystosowany do pracy. (Chociaż dla mnie trudniej jest napisać transformację w XSLT niż nagrywać makro Vima, ale jeśli potrzebujesz tego często, może to być opłacalna inwestycja). Możesz nawet wywołać go z poziomu Vima: :%!xsltproc ...

Przykład XSLT 1.0 Arkusz stylów ...

<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

To jest o wiele lepsze podejście. Czy mógłbyś dodać przykład XSLT do twojej odpowiedzi? Jeśli wolisz, mogę dodać własną odpowiedź: –

+0

@DanielHaley: Jasne, śmiało! Byłoby miło mieć krótki przykład ilustrujący ten punkt. –

Powiązane problemy