Home > Back-end >  Power shell XML node update automatically encode <> charactors
Power shell XML node update automatically encode <> charactors

Time:08-24

I am writing a powershell script to create a xml file which i later feed into azure pipeline. Issue is this generate an encoded output with < , > being converted, which is not in a correct xml format enter image description here I understand this is related to automatic encoding. Some help to prevent this is appreciated

$myitems =
@([pscustomobject]
@{AssertName="Joe";TestPass=$true;},
[pscustomobject]
@{AssertName="Sue";TestPass=$false;},
[pscustomobject]
@{AssertName="Cat";TestPass=$true;})

Set-Content $path <?xml version="1.0"?><testsuites></testsuites>'

$xml = New-Object XML
$xml.Load($path)
$element =  $xml.SelectSingleNode("testsuites")
$innerText=""
foreach ($item in $myitems )
{
  $innerText=$innerText   '<testsuite errors="0" failures="0" id="0" name="$item.AssertName"  tests="1"><testcase classname="some.class.name" name="Test1" time="123.345000"/></testsuite>'
}

[xml] $xml = Get-Content -Raw $path
$xml.testsuites = $innerText
$xml.Save($path)

CodePudding user response:

One way to do this is to use an XmlWriter to build up your document element by element. The XmlWriter automatically takes care of the encoding.

$path = "$PSScriptRoot\test.xml"

$myitems = @(
    [pscustomobject] @{AssertName="Joe";TestPass=$true}
    [pscustomobject] @{AssertName="Sue";TestPass=$false}
    [pscustomobject] @{AssertName="Cat";TestPass=$true}
)
    
$writerSettings = [Xml.XmlWriterSettings] @{
    Encoding = [Text.Encoding]::UTF8
    Indent = $true
    IndentChars = "`t"
    WriteEndDocumentOnClose = $true  # Write document end tag automatically 
}
$writer = [xml.XmlWriter]::Create( $path, $writerSettings )

$writer.WriteStartDocument()   # writes the XML declaration
$writer.WriteStartElement('testsuites')

foreach ($item in $myitems )
{
    # Indentation is used to show the nesting of the XML elements
    $writer.WriteStartElement('testsuite')
        $writer.WriteAttributeString('errors', 0)
        $writer.WriteAttributeString('failures', 0)
        $writer.WriteAttributeString('id', 0)
        $writer.WriteAttributeString('name', $item.AssertName)
        $writer.WriteAttributeString('tests', 1)
        $writer.WriteStartElement('testcase')
            $writer.WriteAttributeString('classname', 'some.class.name')
            $writer.WriteAttributeString('name', 'Test1')
            $writer.WriteAttributeString('time', '123.345000')
        $writer.WriteEndElement()
    $writer.WriteEndElement()
}

# Very important - writes document end tag and closes the file
$writer.Dispose()  

Output:

<?xml version="1.0" encoding="utf-8"?>
<testsuites>
    <testsuite errors="0" failures="0" id="0" name="Joe" tests="1">
        <testcase classname="some.class.name" name="Test1" time="123.345000" />
    </testsuite>
    <testsuite errors="0" failures="0" id="0" name="Sue" tests="1">
        <testcase classname="some.class.name" name="Test1" time="123.345000" />
    </testsuite>
    <testsuite errors="0" failures="0" id="0" name="Cat" tests="1">
        <testcase classname="some.class.name" name="Test1" time="123.345000" />
    </testsuite>
</testsuites>

CodePudding user response:

The way to do this is create an new xml document from your string and import the concerned node (ImportNode) in the main document and than append the child (AppendChild) to the specific node:

$myitems =
    @{ AssertName="Joe"; TestPass=$true },
    @{ AssertName="Sue"; TestPass=$false },
    @{ AssertName="Cat"; TestPass=$true }

$Main = [xml]'<?xml version="1.0"?><testsuites></testsuites>'

foreach ($item in $myitems) {
    $String = '<testsuite errors="0" failures="0" id="0" name="'   $item.AssertName   '" tests="1"><testcase classname="some.class.name" name="Test1" time="123.345000"/></testsuite>'
    $Xml = [xml]$String
    $Node = $Main.ImportNode($Xml.testsuite, $True)
    $Null = $Main.SelectSingleNode('testsuites').AppendChild($Node)
}
[System.Xml.Linq.XDocument]::Parse($Main.OuterXml).ToString()

<testsuites>
  <testsuite errors="0" failures="0" id="0" name="Joe" tests="1">
    <testcase classname="some.class.name" name="Test1" time="123.345000" />
  </testsuite>
  <testsuite errors="0" failures="0" id="0" name="Sue" tests="1">
    <testcase classname="some.class.name" name="Test1" time="123.345000" />
  </testsuite>
  <testsuite errors="0" failures="0" id="0" name="Cat" tests="1">
    <testcase classname="some.class.name" name="Test1" time="123.345000" />
  </testsuite>
</testsuites>
  • Related