Reputation: 197
I am trying to fetch a particular word from an xml by using sfk.exe tool. What it is doing is its fetching the whole sentence/line where the word exists instead of just that word. I want to fetch that word and store it in a temp file to be later stored in a variable. These words will change, basically its the name of the client and it would vary depending on which client's xml is it.
sfk find "C:\Env\Test\test.xml" "Name" > %temp%\Test.tmp
The above line of code fetches the following:
<Org Updated="date" Owner="Test" Version="2/1/3/4"Database="Test" Client="Name">
So basically its getting me the whole line whereas i only want to get "Name" without the quotes.
Upvotes: 0
Views: 373
Reputation: 30113
Although Windows batch can be kind of lame handling xml
, this (quite simple) case could be solved using a (quite simple) script providing additional preliminary assumptions on structure of parsed line(s).
However, the following solution lays emphasis on (as far as possible) universal approach with no premises on position of Client=
attribute inside the containing tag, or its unicity (singularity) inside a line, or number of preceding "
double quotes etc. etc.:
@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
for /F "delims=" %%G in ('
findstr /i /r "\<Client=" "D:\bat\SO\files\q44533501_input.xml"
') do (
rem ECHO=merely debugging output
ECHO %%G
set "_line=%%~G"
call :lineFound
)
goto :eof
:lineFound
rem remove cmd-poisonous characters `<` and `>` (replace them with spaces)
set "_line=%_line:<= %"
set "_line=%_line:>= %"
set "_takeNextItem="
rem parse
for %%g in ( %_line% ) do (
if defined _takeNextItem (
set "_takeNextItem="
set "_client=%%~g"
call :clientSet
) else (
if /I "%%~g" == "Client" set "_takeNextItem=%%~g"
)
)
goto :eof
:clientSet
rem ECHO=merely debugging output;
rem handle %_client% variable in desired manner instead
ECHO(%_client%
goto :eof
Of course, you could use sfk find "C:\Env\Test\test.xml" "Client="
command instead of my findstr /i /r "\<Client=" "D:\bat\SO\files\q44533501_input.xml"
at the 4th line.
Sample output (includes debugging ECHO %%G
to show possible variability of input xml
file):
==> D:\bat\SO\q44533501.bat
<Org Updated="date" Owner="Test" Version="2/1/3/4" Database="Test" Client="Name">
Name
<Org Updated="date" Database="Test" Client="Name2" Owner="Test" Version="2/1/3/4">
Name2
<Org Updated="yesterday" Client="Name3"></Org><Org Client="Name4" Updated="today">
Name3
Name4
==>
Edit. To explain the :lineFound
section, let's take look at FOR
command (it is mostly used to process files, but you can also process text strings):
Conditionally perform a command on several files. Syntax FOR %%parameter IN (set) DO command Key set : A set of one or more files, separated by any standard delimiter. Wildcards can be used. command : The command to carry out, including any command-line parameters. %%parameter : A replaceable parameter: e.g. in a batch file use %%G (on the command line %G)
and utilise the fact that a xml
line we want to parse contains just standard delimiters mentioned above in set
description, see Delimiters:
Delimiters separate one parameter from the next - they split the command line up into words.
Parameters are most often separated by spaces, but any of the following are also valid delimiters:
- Comma (,)
- Semicolon (;)
- Equals (=)
- Space ( )
- Tab ( )
Some example might help: for %g in ( %_line% ) do …
loop processes, item by item, the _line
variable after splitting it using standard delimiters as item separators. In principle, we obtain a sequence where each attribute name is followed by attribute value (but tag name as the first item):
==> for %g in ( %_line% ) do @echo %g
Org
Updated
"date"
Database
"Test"
Client
"Name2"
Owner
"Test"
Version
"2/1/3/4"
==>
Note that _line
variable is hard-coded, for this particular sample case, as
==> set "_line=<Org Updated="date" Database="Test" Client="Name2" Owner="Test" Version="2/1/3/4">"
==> set "_line=%_line:<= %"
==> set "_line=%_line:>= %"
==> set _line
_line= Org Updated="date" Database="Test" Client="Name2" Owner="Test" Version="2/1/3/4"
Upvotes: 1
Reputation: 34899
Although batch files are not the best choice for processing XML data as they do not support them natively, I want to show you a way to do what you want:
@echo off
rem // Capture the output of the `find` command (`sfk` command is not necessary):
for /F "delims=" %%L in ('
^< "C:\Env\Test\test.xml" find /I " Client="
') do (
rem // Store found line in variable:
set "LINE=%%L"
setlocal EnableDelayedExpansion
rem /* Remove everything up to and including the first occurrence of ` Client`
rem from the string; then split off the leading `=` and the training `>`;
rem finally, remove the surrounding `""` from the remaining string: */
for /F "delims==>" %%I in ("!LINE:* Client=!") do (
endlocal
rem // Return the extracted string:
echo(%%~I
)
)
This works only when there is a single occurrence of SPACE + Client
in each applicable line, followed by an =
-sign. Furthermore, this Client=
attribute must be the last one in the containing tag, hence the whole attribute definition Client="Name"
must be immediately followed by >
.
Upvotes: 1
Reputation: 38589
If the line layout doesn't change then you could try this:
Set "Name=Microsoft"
For /F Tokens^=10^ Delims^=^" %%A in (
'Find /I "%Name%"^<"C:\Env\Test\test.xml"') Do Echo "%%A"
As a side note, were you to search for Client=
you could probably simplify it further:
For /F Tokens^=10^ Delims^=^" %%A in (
'sfk find "C:\Env\Test\test.xml" "Client="') Do Echo "%%A"
I have used both the Find
and sfk
commands, they may be interchanged as you see fit.
Upvotes: 1