1

I have an XML file with this format (there could be some leading spaces):

    <Latitude>23.1138</Latitude>
    <Longitude>8.2898</Longitude>
    ...
    <Latitude>19.6247</Latitude>
    <Longitude>-7.3267</Longitude>
    ...
    <Latitude>49.4141</Latitude>
    <Longitude>15.374</Longitude>

Using Vim, I would like to convert each line to Cesium's KML format like this:

    <Point><coordinates>15.374,49.4141</coordinates></Point>

It is important to note KML puts the longitude first (contrary to every other standard). Any help would be appreciated.

  • 1
    Are you using vi or vim? I did try it on your input, and it worked on my system. – Tumbler41 May 6 '16 at 19:55
  • 1
    Oh, also is there whitespace before the the <> tags? I didn't account for that. – Tumbler41 May 6 '16 at 20:01
  • Sorry for the delay. I am using Vim. The whitespace are spaces, not tabs. Your answer was correct. Thanks for your help. – Jeff Diederiks May 9 '16 at 13:56
3

I've come up with a search and replace function that should work for you:

:%s/\(\s*\)<Latitude>\(-\=\d\+\.\d\+\)<\/Latitude>\_.\s*<Longitude>\(-\=\d\+\.\d\+\)<\/Longitude>/\1<Point><coordinates>\3,\2<\/coordinates><\/Point>/

Make sure to save your work as this command is destructive.

:%s Does a search and replace over the all lines. I've swapped the two by using memory parenthesis \(\) and then using backreferences in reverse order. ie. \2\1.

Edit: I've updated the function to take whitespace before the <Longitude> tags into account.

|improve this answer|||||
3

Think of the macros! Really, the regexps by Tumblr41 and Jair Lopez are freakishly smart, but can you really reproduce that in a different case in acceptable time? Here's how I would do it (cursor on line 1):

  • qq record into buffer q
  • ^ go to beginning of line
  • "byit yank lattitude in buffer b
  • j go to next line
  • "ayit yank longitued in buffer a
  • o new line below line 2 (should be indented correctly)
  • <Ctrl-r>a,<Ctrl-r>b<Esc> to put the coordinates there in the right order
  • I<Point><coordinates><Esc>A</Point></coordinates><Esc> to input the other tags
  • kk2dd to delete the superflous lines
  • j to go to the next line, that's not yet converted
  • q to stop recording

This might be more keystrokes, but will take little time to get right, and it doesn't really matter if you use ineffective motions, all will be replayed by the macro, and you just need to input it once.

|improve this answer|||||
1

If the XML file only have lines in that format you could try this shorter command:

:%s/\v\S{-}([0-9.-]+)\_.{-}([0-9.-]+)\S*/<Point><coordinates>\2,\1<\/coordinates><\/Point>

Explanation:

  • \v stands for “Very magic”. It means that in the pattern after it all ASCII characters except 0-9, a-z, A-Z and _ have a special meaning, so it isn't necessary to prefix them with (\).
  • \S matches any character except whitespaces.
  • {-} is the non-greedy version of *, i.e., matches 0 or more of the preceding atom, as few as possible (see :help non-greedy and this answer for details)
  • \S{-} matches the XML tag and without considering any leading spaces.
  • [0-9.-]+ matches a number.
  • ([0-9.-]+) preserves the fist number in a sub-expression so that it's possible to reuse it in the substitution part with \1.
  • \_. matches any single character or end-of-line.
  • \_.{-} matches the </Latitude> tag, end-of-line, any leading space on the next line, and the <Longitude> tag.
  • ([0-9.-]+) preserves the second number in a sub-expression so that it's possible to reuse it with \2.
  • \S* matches the </Longitude> tag.
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.