-1

I have an XML file of the type

....
<sometag>
<tag attr_name1="long filename1" />
<tag attr_name2="long filename2" />
....
</sometag>
....

Before </sometag> I want to add <tag attr_name="long filename" /> so far the code in my Batch Script for Windows is:

@echo off
setlocal enableDelayedExpansion
set "newValue=^<tag attr_name="long filename" /^>
set newline=^& echo.
type "File.xml"|replace "(</tag>)" "!newValue!$1" >dupFile.xml
move /y "dupFile.xml" "File.xml"

I get "Path not found - </tag>" and File.xml contains "No Files Replaced". I know its not best practice to edit XML from batch file but can't use third party executables unfortunately. Can someone please help with where I'm going wrong?

Also I've checked the thread about changing data between tags in XML using batch file, when I use the suggested code there and alter to my requirement i get the above error.

Community
  • 1
  • 1
DivyaJyoti Rajdev
  • 734
  • 1
  • 9
  • 15
  • You cannot use php, python or perl ? – Pedro Lobito May 26 '16 at 23:57
  • Or even Powershell? – SomethingDark May 27 '16 at 00:01
  • Also whatever `replace` is, that's third-party since batch has no native replace command. – SomethingDark May 27 '16 at 00:03
  • Cannot unfortunately use Java, PhP, Python, Perl, Powershell, as this is for automation of server component installation on client side. Replace is just the "REPL" command – DivyaJyoti Rajdev May 27 '16 at 15:49
  • @DivyaJyotiRajdev Assume for a minute that you're mistaken about PowerShell being incapable of "automation of server component installation on client side", whatever that technobabble is intended to convey. Continue until realization hits that this is, in fact, what is actually happening, and that you were mistaken. [PowerShell v2 is included with Windows 7](https://blogs.technet.microsoft.com/josebda/2009/11/25/download-for-powershell-v2-for-windows-7-no-need-its-already-there/); Win 8 through 10 also include PowerShell; and VBScript / JScript have been included in Windows for much longer. – rojo May 27 '16 at 16:08
  • There is a native `replace` command in Windows, but its purpose is to replace files rather than to replace text in strings -- type `replace /?` in command prompt for help... Or are you using a third-party tool called `replace`? if so, you need to tell us what it is... – aschipfl May 28 '16 at 09:12

1 Answers1

5

If </sometag> appears only once in your XML and if it won't screw up the hierarchy inserting your new <tag> node on the line before, you could just loop through your XML file with a for /F loop, checking whether each line contains </sometag>. When found, simply echo your new <tag> prior to echoing the matched line.

@echo off
setlocal

>"newfile.xml" (
    for /f "usebackq delims=" %%I in ("xmlfile.xml") do (
        set "line=%%I"
        setlocal enabledelayedexpansion
        if not "!line!"=="!line:/sometag=!" (
            echo ^<tag attr_name="long filename" /^>
        )
        endlocal
        echo(%%I
    )
)

type "newfile.xml"

But really, assuming your XML is fully valid, the most elegant solution is to parse the XML as structured data, rather than as complicated text to hack and scrape. That way it doesn't matter whether your code is beautified, minified, uglified, or whatever. The parser still understands it, regardless of indentation and line breaks. You can do this with languages already built into Windows -- VBScript, JScript, PowerShell, C#, and the list goes on. Batch might be the only language with which you're familiar, but it isn't the only language available in a base install of Windows. Here's a quick and dirty batch + PowerShell hybrid script to demonstrate. (Save it with a .bat extension.)

<# : batch portion (within a multiline PowerShell comment)
@echo off & setlocal

set "infile=test.xml"
set "parentNode=sometag"
set "newTag=tag"
set "newAttr=attr_name"
set "attrVal=long filename"
set "outfile=new.xml"

powershell -noprofile -noninteractive "iex (${%~f0} | out-string)"
type "%outfile%"

goto :EOF

: end batch (multiline comment) / begin PowerShell hybrid code #>

[xml]$xml = gc $env:infile
$parent = $xml.documentElement.selectSingleNode("//$env:parentNode")
$new = $xml.createElement($env:newTag)
[void]$new.setAttribute($env:newAttr, $env:attrVal)
[void]$parent.appendChild($new)
$xml.save($env:outfile)
rojo
  • 24,000
  • 5
  • 55
  • 101
  • Thank you that worked quite well, I'd appreciate if you could help debug where I was going wrong with trying to capture regex? Meanwhile I'll explore the better PowerShell alternative solutions – DivyaJyoti Rajdev May 27 '16 at 16:43
  • @DivyaJyotiRajdev Sorry, I have no experience with `replace.exe`. Indeed, I've never heard of it before your question. – rojo May 27 '16 at 16:54