With PowerShell, I want to add several sub-elements into an XML tree.
I know to ADD ONE element, I know to add one or several attributes, but I don't understand how to ADD SEVERAL elements.
One way whould be to write a sub-XML tree as text
But I can't use this method because the elements are not added at once.
To add one element, I do that:
[xml]$xml = get-content $nomfichier
$newEl = $xml.CreateElement('my_element')
[void]$xml.root.AppendChild($newEl)
Works fine. This give me this XML tree:
$xml | fc
class XmlDocument
{
root =
class XmlElement
{
datas =
class XmlElement
{
array1 =
[
value1
value2
value3
]
}
my_element = <-- the element I just added
}
}
Now I want to add a sub element to 'my_element'. I use a similar method:
$anotherEl = $xml.CreateElement('my_sub_element')
[void]$xml.root.my_element.AppendChild($anotherEl) <-- error because $xml.root.my_element is a string
[void]$newEl.AppendChild($anotherEl) <-- ok
$again = $xml.CreateElement('another_one')
[void]$newEl.AppendChild($again)
This give this XML tree (partialy displayed):
my_element =
class XmlElement
{
my_sub_element =
another_one =
}
Those are attributes, not sub-elements.
Sub-elements would be displayed as this:
my_element =
[
my_sub_element
another_one
]
Question : How do I add several sub-elements, one at a time?
Have a look to the following example :
# Document creation
[xml]$xmlDoc = New-Object system.Xml.XmlDocument
$xmlDoc.LoadXml("<?xml version=`"1.0`" encoding=`"utf-8`"?><Racine></Racine>")
# Creation of a node and its text
$xmlElt = $xmlDoc.CreateElement("Machine")
$xmlText = $xmlDoc.CreateTextNode("Mach1")
$xmlElt.AppendChild($xmlText)
# Creation of a sub node
$xmlSubElt = $xmlDoc.CreateElement("Adapters")
$xmlSubText = $xmlDoc.CreateTextNode("Network")
$xmlSubElt.AppendChild($xmlSubText)
$xmlElt.AppendChild($xmlSubElt)
# Creation of an attribute in the principal node
$xmlAtt = $xmlDoc.CreateAttribute("IP")
$xmlAtt.Value = "128.200.1.1"
$xmlElt.Attributes.Append($xmlAtt)
# Add the node to the document
$xmlDoc.LastChild.AppendChild($xmlElt);
# Store to a file
$xmlDoc.Save("c:\Temp\Temp\Fic.xml")
Edited
Remark : Using a relative path in Save will not do what you expect .
I prefer creating xml by hand, instead of using API to construct it node by node, as imho by hand it will be much more readable and more maintable.
Here is an example:
$pathToConfig = $env:windir + "\Microsoft.NET\Framework64\v4.0.30319\Config\web.config"
$xml = [xml] (type $pathToConfig)
[xml]$appSettingsXml = @"
<appSettings>
<add key="WebMachineIdentifier" value="$webIdentifier" />
</appSettings>
"@
$xml.configuration.AppendChild($xml.ImportNode($appSettingsXml.appSettings, $true))
$xml.Save($pathToConfig)
Check this code-sample. It has everything you need to create XML from scratch:
function addElement($e1, $name2, $value2, $attr2)
{
if ($e1.gettype().name -eq "XmlDocument") {$e2 = $e1.CreateElement($name2)}
else {$e2 = $e1.ownerDocument.CreateElement($name2)}
if ($attr2) {$e2.setAttribute($value2,$attr2)}
elseif ($value2) {$e2.InnerText = "$value2"}
return $e1.AppendChild($e2)
}
function formatXML([xml]$xml)
{
$sb = New-Object System.Text.StringBuilder
$sw = New-Object System.IO.StringWriter($sb)
$wr = New-Object System.Xml.XmlTextWriter($sw)
$wr.Formatting = [System.Xml.Formatting]::Indented
$xml.Save($wr)
return $sb.ToString()
}
...now let's use both functions to create and display a new XML-object:
$xml = New-Object system.Xml.XmlDocument
$xml1 = addElement $xml "a"
$xml2 = addElement $xml1 "b"
$xml3 = addElement $xml2 "c" "value"
$xml3 = addElement $xml2 "d" "attrib" "attrib_value"
write-host `nFormatted XML:`r`n`n(formatXML $xml.OuterXml)
the result looks like this:
Formatted XML:
<?xml version="1.0" encoding="utf-16"?>
<a>
<b>
<c>value</c>
<d attrib="attrib_value" />
</b>
</a>
For anyone else visiting this.
I had issues because my parent document had a namespace, and the ImportNode
was adding an empty xmnls=""
element to the imported xml, causing issues with my app
Extending on answer above. To get around this, wrap it in a dummy node, with namespace set from parent doc
$pathToConfig = $env:windir + "\Microsoft.NET\Framework64\v4.0.30319\Config\web.config"
$xml = [xml] (type $pathToConfig)
$root = $xml.get_DocumentElement()
$namespaceuri = $root.NamespaceURI
[xml]$appSettingsXml = @"
<Dummy xmlns="$namespaceuri">
<appSettings>
<add key="WebMachineIdentifier" value="$webIdentifier" />
</appSettings>
</Dummy>
"@
$xml.configuration.AppendChild($xml.ImportNode($appSettingsXml.Dummy.appSettings, $true))
$xml.Save($pathToConfig)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.