gec100
gec100

Reputation: 51

Windows batch to read path from XML

I need to read a path from an attribute in an XML file but spaces are making me problems.

@echo off

:: Write a VBS file for getting modfolder from gameSettings.xml
> "%TEMP%\moddir.vbs" (
echo.Dim oXml: Set oXml = CreateObject^("Microsoft.XMLDOM"^)
echo.oXml.Load WScript.Arguments.Item^(0^)
echo.Dim oDoc: Set oDoc = oXml.documentElement
echo.
echo.For Each node In oDoc.childNodes
echo.   If ^(node.nodeName = "modsDirectoryOverride"^) And ^(node.getAttribute^("active"^) = "true"^) Then
echo.       WScript.Echo node.getAttribute^("directory"^)
echo.   End If
echo.Next
echo.Set oXml = Nothing
)

:: Setting Mod directory
SETLOCAL
for /f %%i in ('cscript %TEMP%\moddir.vbs "%UserDocs%\My Games\FarmingSimulator2017\gameSettings.xml" //Nologo') do set "moddir=%%i"

echo moddir = %moddir%

The line in the XML file is:

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<gameSettings revision="11">
<modsDirectoryOverride active="true" directory="D:\games\Farming Simulator\Farming simulator 17\Mods"/>
</gameSettings>

The variable moddir is set to D:\games\Farming although it should be D:\games\Farming Simulator\Farming simulator 17\Mods.

Upvotes: 0

Views: 320

Answers (2)

Aacini
Aacini

Reputation: 67216

I offer you a pure Batch file alernative solution that is simpler, but have the disadvantage that it only works with the xml file format you shown.

The findstr command can extract lines from a file that have a given string. For example, findstr "modsDirectoryOverride" "gameSettings.xml" command show this line:

<modsDirectoryOverride active="true" directory="D:\games\Farming Simulator\Farming simulator 17\Mods"/>

If we separate this line based on for /F command, that use the space as default separator, and include these options: for /F "tokens=1,2*" %%a in ('previous line') do ..., you'll realize that the for parameters have these values:

%%a have <modsDirectoryOverride
%%b have active="true"
%%c have directory="D:\games\Farming Simulator\Farming simulator 17\Mods"/>

Then, we can execute set %%b and set %%c commands, that would be equivalent to these commands:

set active="true"
set directory="D:\games\Farming Simulator\Farming simulator 17\Mods"/>

After that, you just need to test if %active% is "true" to show the directory, and that is it! ;) The only detail is that the value of %directory% start with quote and ends with "/>, so these characters must be stripped from the output:

@echo off
setlocal

for /F "tokens=1,2*" %%a in ('findstr "modsDirectoryOverride" "gameSettings.xml"') do (
   set %%b
   set %%c
)
if %active% equ "true" echo %directory:~1,-3%

Upvotes: 1

Magoo
Magoo

Reputation: 80023

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q41196420.txt"
FOR /f "usebackqtokens=1,3delims=<=>/" %%a IN ("%filename1%") DO (
 IF "%%~a"=="modsDirectoryOverride active" ECHO dir=%%~b
)

GOTO :EOF

You would need to change the setting of sourcedir to suit your circumstances.

I used a file named q41196420.txt containing your data for my testing.

Here's an easy way - simply select suitable tokens and delimiters and filter with an if


Best to provide the problem to be solved, not a solution-to-fix alone.

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q41196420.txt"
FOR /f "usebackqtokens=1-7delims=<=>/" %%a IN ("%filename1%") DO (
ECHO + %%a + %%b + %%c + %%d + %%e + %%f + %%g +
REM note content of "%%x" - %%~x = %%x minus quotes at either end
REM we may need to tokenise "%%a" using spaces as delimiters
 FOR /f "tokens=1*delims= " %%m IN ("%%a") DO (
 REM %%a..%%g, %%m and %%n are in-context
  ECHO + %%m + %%n
  REM same formula for "%%b"
  FOR /f "tokens=1*delims= " %%p IN ("%%b") DO (
  REM %%a..%%g, %%m and %%n are in-context
   ECHO + %%p + %%q
   ECHO + %%a + %%b + %%c + %%d + %%e + %%f + %%g + %%m + %%n + %%p + %%q +
   REM So, select your parts. if /i=case-insensitive since I abhor CaMeLcAsE
   IF /i "%%~m"=="modsdirectoryoverride" IF /i "%%n"=="active" IF /i "%%~p"=="true" ECHO.&ECHO ***Directory=%%~c*** or ***Directory=%%c*** as you wish
  )
 )
 REM %%a..%%g are in-context, %%m and %%n are not
 ECHO.
)

GOTO :EOF

If you read the documentation (for /? |more from the prompt) then you'll likely be befuddled.

The code above displays how the line can be disassembled in batch, the important point being the conditional selection of the directoryname.

Take any line of text. This could be one of a series of lines in a file, a series of lines output from a command or even a variable.

First, you use delims to specify what delimiters to use. The line is seen as a series of tokens separated by a [sequence of] delimiter[s]

so abc/123:ghij/:/hello is seen as tokens abc, 123, ghij and hello if delims is set to /:. By default, it is set to comma and space.

The tokens keyword assigns the selected strings to metavariables (the loop-control variables+). If the metavariable is %%a then the lowest selected token is assigned to %%a, the next lowest to %%b and so on. * is a special which means "everything after the highest token selected, including delimiters". tokens defaults to 1.

So, applying tokens=1,3 to the above tokenised abc/123:ghij/:/hello with metavariable %%a will set %%a=abc (1st) and %%b=ghij (3rd).

Beyond that, you may need usebackq to allow a filename in quotes (required if the full name includes spaces) to be read; if usebackq is omitted, a quoted string will be used literally.

Upvotes: 1

Related Questions