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.

3
  • 1
    Are you using vi or vim? I did try it on your input, and it worked on my system.
    – Tumbler41
    May 6, 2016 at 19:55
  • 1
    Oh, also is there whitespace before the the <> tags? I didn't account for that.
    – Tumbler41
    May 6, 2016 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. May 9, 2016 at 13:56

3 Answers 3

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.

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.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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