0

I have this script, to read xml file. The file contains coordinates and I want to list the coordinates:

@echo off
setlocal EnableDelayedExpansion

FOR %%K IN (*.xml) DO (
SET K=%%K
SET K=!K:~0,-4!
SET "prep=0"

    REM READ DATA
    FOR /F "tokens=*" %%X IN (!K!.kml) DO (
    if !prep! == 1 (
    echo %%X
    pause
      FOR /F %%L IN ("%%X") DO (
      SET L=%%L
      IF NOT "!L:~0,1!" == "<" (
        echo %%L
        )       
      )
      SET "prep=0"
    )
    if "%%X" == "<coordinates>" ( SET "prep=1" )
    )
)

I got these result:

14.63778004128814,49.50141683426452,0 14.63696238385996,49.48348965654706,0 14.6
8840586504191,49.47901033971912,0 14.68589371304878,49.49939179836829,0 14.63778
004128814,49.50141683426452,0 </coordinates>
Press and key to continue...
14.63778004128814,49.50141683426452,0
Press and key to continue...

First you see the line with coordinates. Second, in the 3rd loop, there are coordinates printed. But I have only one pair of coordinates printed... If I will press a key again, the batch finishes without printing next columns. Can you help?

Edit After the answer has been posted, I have question 1) could we use this:

SET LF=^


setlocal EnableDelayedExpansion
... (next code) ...
set "var=!var: =%LF%!"    

So when there is no delayed LF variable, we could embed it. Or not?

And 2) why in your code

for %%L in ("!LF!") do set "X=!X: =%%~L!"

Did you use %%~L and not just %%L

John Boe
  • 3,501
  • 10
  • 37
  • 71

1 Answers1

1

Your immediate problem is that FOR /F does not iterate the tokens in a line. It simply parses each token that you ask for. If you don't specify a "tokens" option, then it defaults to "tokens=1" - it only parses the first token in the line.

However, FOR /F will treat a string as multiple lines if the string contains linefeed characters. It will then iterate each line like you want. The trick is to replace your space delimiter with a line feed character. There are multiple methods that can do the job, but I will show what I think is the easiest to work with.

First define a variable containing a single linefeed

set LF=^


::The two blank lines above are critical for the definition of the line feed

The next trick is to replace spaces in your variable with linefeeds. Normally substituion using a variable for the replacement would look something like set "var=!var:search=%replaceVar%!". But that won't work for the LF variable - it is difficult to work with the LF variable using normal expansion. It is much easier to use delayed expansion. We can't embed delayed expansion within delayed expansion, but we can transfer the value of LF to a simple FOR variable and use for %%L in ("!LF!") do set "var=!var: =%%~L!"

One thing about your code I do not understand - your initial FOR loop is iterating accross all the .KML files. You strip off the extension using a substring operation. There is a much easier way to do that without using an environment variable: %%~nK will give the base name of the file without the extension. But why do that at all when you turn around and append the extension again?

I used the %%K value directly - I added the USEBACKQ option and added quotes to allow for spaces in the file name.

Here is code that should do what you are expecting.

@echo off
setlocal EnableDelayedExpansion

::define a variable containing a linefeed character
set LF=^


::Above 2 blank lines are part of the LF definition, do not remove

for %%K in (*.kml) do (
  set "prep=0"
  for /f "usebackq tokens=*" %%X in ("%%K") do (
    if !prep! == 1 (
      echo %%X
      pause
      set "ln=%%X"
      for %%L in ("!LF!") do set "ln=!ln: =%%~L!"
      for /f %%L in ("!ln!") do (
        set L=%%L
        if not "!L:~0,1!" == "<" (
          echo %%L
        )
      )
      set "prep=0"
    )
    if "%%X" == "<coordinates>" ( set "prep=1" )
  )
)

BUT - I think you have a bigger problem. I am worried that you are setting yourself up for a world of pain by using batch to parse XML. You are assuming the XML will always be layed out the same way. There are countless valid ways of adding or subtracting linefeeds and white space into the XML document that would break your algorithm. Can you be sure all your input files came from the same source and will always be formatted like you expect? I think you really should be using XSLT to parse and transform your XML document into a naked list of coordinates.

Answsers to additional questions

1) set "var=!var: =%LF%!" will not work - Regular expansion of LF requires escape sequences and multiple expansions. This will work: set "var=!var: =^%LF%LF%!"

The escape sequences for %LF% can get very tricky, so I try to avoid them.

2) Regarding for %%L in ("!LF!") do set "X=!X: =%%~L!", note that it is a simple FOR, not FOR /F. The !LF! must be quoted or else FOR will not read it. But the FOR statement preserves the quotes (unlike FOR /F), so I need %%~L to remove the enclosing quotes.

There is a very important distinction between FOR and FOR /F with regard to linefeeds. FOR will preserve quoted linefeeds, whereas FOR /F treats the linefeed as a line delimiter and iterates each line, so the linefeeds are not preserved.

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • Thanks. It is long answer (replacing solution is so simple). I will comment this multiple times later. Now just comment for xml parsing. No, I am not going to create xml parser. I need only this one information. This xml is generated by program and should be always same. – John Boe Apr 07 '12 at 14:35
  • The reason why I removed extension is that I create folder after this code. Also I will write coordinates in line format to a file called temp/!K!.txt – John Boe Apr 07 '12 at 15:01
  • Why I cannot to add quotes like this: SET "LF=^" (the newline characters dispeared here) – John Boe Apr 07 '12 at 15:12
  • @user1141649 - Prior comment - that makes sense. Your original code certainly works. I think `%%~nK` is much simpler than `set "K=%%K" & set "K=!K:0,-4!"`. – dbenham Apr 07 '12 at 15:18
  • @user1141649 - The LF definition must be as originally written. For explanation, read http://stackoverflow.com/questions/6379619/explain-how-dos-batch-newline-variable-hack-works/6379861#6379861 – dbenham Apr 07 '12 at 15:20
  • I will enter code in the original answer because I cannot here paste code. (question edited) – John Boe Apr 07 '12 at 15:25
  • The additional answers are very helpful thanks. Right now. I solve one more problem in the 3rd loop. The first coordinates are printed twice: "14.63778004128814,49.50141683426452" "14.63778004128814,49.50141683426452" "14.63696238385996,49.48348965654706" "14.68840586504191,49.47901033971912" "14.68589371304878,49.49939179836829" "14.63778004128814,49.50141683426452" I did isolate the lines to quotes... Any idea why the first line is duplcated? – John Boe Apr 07 '12 at 16:58
  • Nothing in the code I posted would duplicate coordinates. Have you checked to verify your input does not have duplicates? I noticed that the last coordinate is a duplicate of the first in your original post. – dbenham Apr 07 '12 at 17:13
  • I have incorrect path to delete the file before I start to redirect output to file. Problem solved. Now it works nice. – John Boe Apr 07 '12 at 17:54