2
<Document SeqNum="1">
  <UserDocNum>1</UserDocNum>
  <DocName>CARD DISPUTE PACKET-DEBIT</DocName>
  <Institution>149</Institution>
  <Indexes>
    <Index Name="DOC DATE">08/03/2023</Index>
    <Index Name="BRANCH">2</Index>
  </Indexes>

I have this XML structure on a file called Synergy.xml I need to add a line after DOCName or Before Institution called Member. It would look like this

  <DocName>CARD DISPUTE PACKET-DEBIT</DocName>
  <Cabinet>MEMBER</Cabinet>
  <Institution>149</Institution>
  <Indexes>
    <Index Name="DOC DATE">08/03/2023</Index>
    <Index Name="BRANCH">2</Index>
  </Indexes>

I know I have to select the Parent and there is an insertBefore

I am not good with Powershell especially with XML

Thank you

mhughey
  • 31
  • 4

2 Answers2

1

Using Xml Linq

using assembly System
using assembly System.Collections
using assembly System.Xml.Linq
using assembly System.IO

$inputFilename = "c:\temp\test.xml"
$outputFilename = "c:\temp\test1.xml"

$doc = [System.Xml.Linq.XDocument]::Load($inputFilename)
$docName = $doc.Descendants("DocName")[0]

$cabinet = [System.Xml.Linq.XElement]::new([System.Xml.Linq.XName]::Get('Cabinet'),'MEMBER')
$docName.AddAfterSelf($cabinet)

$doc.Save($outputFilename)
jdweng
  • 33,250
  • 2
  • 15
  • 20
1

Assuming that your XML document is stored as an [xml] (System.Xml.XmlDocument) instance in variable $xml:

# Create the new element...
($newEl = $xml.CreateElement('Cabinet')).InnerText = 'MEMBER'

# ... and insert it after the <DocName> element.
$xml.Document.InsertAfter(
  $newEl,
  $xml.Document['DocName']
)

Note:

  • To load your XML file into a [xml] instance, use something like the following:

    ($xml = [xml]::new()).Load((Convert-Path Synergy.xml))
    
    • Note: Situationally, the simpler [xml] $xml = Get-Content -Raw Synergy.xml may work, but it isn't robust - see the bottom section of this answer.
  • $xml.Document['DocName'] mixes PowerShell's dot notation with the [xml]-type-native indexer in order to obtain the <DocName> child element.

    • This is necessary, because $xml.Document.DocName wouldn't return an element object (System.Xml.XmlElement), but - due to the element containing only text - just that text.

    • For details on PowerShell's dot notation for [xml] instances, see this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I tried this based on your notes. And I got a this error. Cannot index into a null array. At R:\Scripts\TestQ2.ps1:9 char:1 + $xml.Document.InsertAfter( + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : NullArray – mhughey Aug 08 '23 at 12:27
  • ````$sourceDir = "C:\temp\Synergy.xml" ($xml = [xml]::new()).Load((Convert-Path $Sourcedir)) # Create the new element... ($newEl = $xml.CreateElement('Cabinet')).InnerText = 'MEMBER' # ... and insert it after the element. $xml.Document.InsertAfter( $newEl, $xml.Document['DocName'] ) ```` – mhughey Aug 08 '23 at 12:29
  • @mhughey: That implies that your XML document has no top-level `` element. If that element is nested inside your document, use dot notation to reach it, e.g. `$xml.TopElement.OtherElement.Document` – mklement0 Aug 08 '23 at 12:38
  • `$xml = [System.Xml.XmlDocument](Get-Content $sourceDir) # Create the new element... ($newEl = $xml.CreateElement('Cabinet')).InnerText = 'MEMBER' # ... and insert it after the element. $xml.Document.InsertAfter($newEl,$xml.Document['DocName'] )` – mhughey Aug 08 '23 at 13:02
  • Still getting the same error. – mhughey Aug 08 '23 at 13:03
  • @mhughey: Your code is in essence the same as the in the comment before; you didn't address the non-existence of the top-level `` element. This answer works with your sample XML. If your real XML is different, you need to adapt it accordingly. – mklement0 Aug 08 '23 at 13:05