How to print angular brackets in XML using powershell

1k Views Asked by At

I want to print the angular brackets(<,>) in powershell, but it is printing to > and < instead respectively. Is there any way I can print those symbols.

I have used \ to overcome the bracket's escape properties and also single inverted commas but the result remains same.

$xml = [xml](Get-Content -Path C:\Users\Desktop\new.xml)
$xml.Deploy.app="$<abc\bc>"
$xml.Save("C:\Users\Desktop\new.xml")

I expected output to be

<?xml version="1.0"?> 
<Deploy>
  <app><abc\bc></app>
</Deploy>

but it printing

<?xml version="1.0"?>
<Deploy>
  <app>&lt;abc\bc&gt;</app>
</Deploy>

Thanks in advance!!

2

There are 2 best solutions below

4
On

XML needs 5 characters to be replaced, because they have special meaning in XML. These characters are <>&'" Here, you can not simply prepend these characters with some escape character like the backslash, instead they need to be converted into named or numbered entities.

As you have noticed, this conversion happens automatically in [xml], but there are also a number of ways to do that manually if needed:

$str = "$<abc\bc>"

1) Using the String .Replace() method:

$str.Replace("&", "&amp;").Replace("'", "&apos;").Replace('"', "&quot;").Replace("<", "&lt;").Replace(">", "&gt;")

2) Using .Net System.Security:

 Add-Type -AssemblyName System.Security
 [System.Security.SecurityElement]::Escape($str)

3) Using System.Xml.XmlDocument:

[xml]$doc = New-Object System.Xml.XmlDocument
$node = $doc.CreateElement("root")
$node.InnerText = $str
$node.InnerXml

4) Using Regex:

$str -ireplace '&#34;|&#x(?:00)?22;|"', '&quot;' `
     -ireplace "&#39;|&#x(?:00)?27;|'", '&apos;' `
     -ireplace '&#60;|&#x(?:00)?3C;|<', '&lt;'   `
     -ireplace '&#62;|&#x(?:00)?3E;|>', '&gt;'   `
     -ireplace '&#38;|&#x(?:00)?26;|&(?!(?:[a-z]+|#[0-9]+|#x[0-9a-f]+);)', '&amp;'

All of the above will convert the XML special characters into entities, so the result will look like this:

$&lt;abc\bc&gt;


If you absolutely don't want the XML special characters to be converted into entities, then there is AFAIK only the option to set the value as a CDATA section, which will wrap your string inside <![CDATA[ and ]]>]. To use that in your example, change the line $xml.Deploy.app="$<abc\bc>" into this:

$xml['Deploy']['app'].AppendChild($xml.CreateCDataSection("$<abc\bc>")) | Out-Null

Now it will print:

<?xml version="1.0"?>
<Deploy>
  <app><![CDATA[$<abc\bc>]]></app>
</Deploy>

To read back this CDATA value as string, you can do either $value = $xml.Deploy.app.InnerText or $value = $xml.Deploy.app.'#cdata-section'

Hope that explains

2
On

This is just how XML works. The less than and greater than characters are reserved/special characters. When a value includes them it will convert them to their escaped forms &lt; and &gt;. What you expect to be output is invalid XML.