2

I want to create a batch script which will do the following: Find specific xml lines, and add specific multiline tags.

For example: Find exactly this set of lines:

<tree_node>
    <rule_name>bla</rule_name>
    <rule_argument>bla</rule_argument>
    <acl_name>bla</acl_name>
</tree_node>

Then add this set of lines afterwards:

<tree_node>
    <rule_name>TEST1</rule_name>
    <rule_argument>TEST2</rule_argument>
    <acl_name>TEST3</acl_name>
</tree_node>

An alternative solution would be to insert the tags at a specific line number. Can anyone help with a solution? I have searched, but not found anything about my problem.

Thanks for the help!

Nikec123
  • 39
  • 6
  • Related dbenham's answer: [Please note - parsing XML with batch is a risky business](http://stackoverflow.com/a/26718487/3439404) – JosefZ Apr 04 '17 at 08:49
  • Why not use a scripting language that can properly read and write XML files? Vbscriipt, Jscript, Powershell. – Squashman Apr 04 '17 at 12:24
  • It would be possible in Powershell- however I don't have any knowhow to do it. Any examples would be welcome. Thanks! – Nikec123 Apr 04 '17 at 12:42

1 Answers1

0

The Batch file below do exactly what you requested:

@echo off
setlocal EnableDelayedExpansion

rem Define CR variable containing a Carriage Return (0x0D)
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"

rem Define LF variable containing a Line Feed (0x0A)
set LF=^
%Do not remove%
%these lines%

rem Define the string to find
set "find=<tree_node>!CR!!LF!"
set "find=!find!    <rule_name>bla</rule_name>!CR!!LF!"
set "find=!find!    <rule_argument>bla</rule_argument>!CR!!LF!"
set "find=!find!    <acl_name>bla</acl_name>!CR!!LF!"
set "find=!find!</tree_node>"

rem Get the number of lines to copy
findstr /N /R /C:"!find!" input.txt > findstr.tmp
for /F "delims=:" %%a in (findstr.tmp) do set /A lines=%%a+4
del findstr.tmp

rem Read from input file
< input.txt (

   rem Copy the appropriate number of lines
   for /L %%i in (1,1,%lines%) do (
      set /P "line="
      echo !line!
   )

   rem Add the new lines
   echo ^<tree_node^>
   echo     ^<rule_name^>TEST1^</rule_name^>
   echo     ^<rule_argument^>TEST2^</rule_argument^>
   echo     ^<acl_name^>TEST3^</acl_name^>
   echo ^</tree_node^>

   rem Copy the rest of lines
   findstr "^"

rem Write to output file
) > output.txt

move /Y output.txt input.txt

For a further description on the method used to find the multi-line string, see this answer.

EDIT: How to define a larger search text

The findstr command have a limit in the length of the multi-line string used to search text in the file. However, you don't need to include each and every character of such a part in the multi-line string! You may use a shorter string comprised of a regex that cover several characters in the file; for example, the .* regex match any number of characters that are delimited by the characters placed before and after it. In this way, you just need to include enough parts in the search text in order to made it unique in the file.

For example, if there is just one <rule_name>bla</rule_name> section in the file, then the same five-lines search string in this code may be defined with this shorter text:

rem Define the string to find
set "find=<tree_node>!CR!!LF!"
set "find=!find!    <rule_name>bla</rule_name>!CR!!LF!"
set "find=!find!.*!CR!!LF!"
set "find=!find!.*!CR!!LF!"
set "find=!find!</tree_node>"
Community
  • 1
  • 1
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • Thanks for this script, it works, but only with short text. When adding a longer text i get an error with findstr is too long. Any help with an alternative solution? PowerShell for instance? The idea is to modify a .xml file to insert new tags after finding specific ones (as in the example above). Thanks! – Nikec123 Apr 07 '17 at 09:09
  • See the edit in my answer... May I ask you to select this as "Best answer" and also upvote it? Thanks! – Aacini Apr 07 '17 at 11:57