3

I have an XML file. I need to replace the language with Swedish.

 <?xml version="1.0" encoding="utf-8"?>
    <usersettings>
      <Language type="string">English</Language>
    </usersettings>

Can you help me?

$xmldata = [xml] (Get-Content $file)
$xmldata.usersettings.Language.'#text'
zagnafey
  • 89
  • 1
  • 6

2 Answers2

3

Assign the new value to the InnerText attribute of the desired node:

$xmldata.usersettings.Language.InnerText = 'Swedish'

# remember to save updated document to disk
$xmldata.Save((Resolve-Path $file).Path)
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
1

To complement Mathias R. Jessen's helpful answer:

Your own approach would have worked too - although it is (a) a bit more obscure, and (b) relies on the target element to already contain text (which is true in your case):

$xmldata.usersettings.Language.'#text' = 'Swedish'

PowerShell's adaptation of the XML DOM (surfacing child elements and attributes as properties) is handy, but remembering the precise rules can be tricky:

  • If a given element only has no content or only text content (a text child node) and also no attributes, it surfaces as a string-valued property on its parent element.

    • You can directly assign a string to such a property to set its text content; e.g.:

      $xml = [xml] '<usersettings><Language>English</Language></usersettings>'
      $xml.usersettings.Language = 'Swedish'
      $xml.OuterXml # output the XML for verification
      
  • By contrast, if an element has attributes and/or child elements, it surfaces as an XmlElement-valued property.

    • A child text node, if any, is represented as adapted property .'#text' (quoting needed), alongside adapted properties representing attributes and child elements, if any.

      $xml = [xml] '<usersettings><Language type="String">English</Language></usersettings>'
      # Due to presence of an *attribute*, assignment must now happen
      # via a property.
      # Property '#text' is the existing text child node (text content).
      $xml.usersettings.Language.'#text' = 'Swedish'
      $xml.OuterXml # output the XML for verification
      
    • Independently, you can use the type-native .InnerText property to replace an element's current child nodes, if any, with a text node, as shown in Mathias' answer.

      $xml = [xml] '<usersettings><Language type="String">English</Language></usersettings>'
      # Due to presence of an *attribute*, assignment must now happen
      # via a property.
      # Property .InnerText replaces all child nodes, if any, with 
      # a child text node (text content).
      $xml.usersettings.Language.InnerText = 'Swedish'
      $xml.OuterXml # output the XML for verification
      

In short:

  • When using PowerShell's property-based adaptation of the XML DOM, you need to be aware of when an XML element becomes a property of type [string] - to which you can assign a string directly - vs. when it becomes an XmlElement-typed property - which requires use of another property to assign text content.

  • That other property can be .'#text', if there's existing text content (a text child node) or - independently of any existing child nodes - .InnerText, but note that the latter quietly replaces any existing child nodes, including element child nodes.

mklement0
  • 382,024
  • 64
  • 607
  • 775