Cheries
Cheries

Reputation: 892

How do I create new element of XML automatically file in PowerShell?

I have a text file with this content:

123asdf
abdfeef
22343sf
dfafdsf

The content of this file is changing.

I want to create an xml file, where one element contains the text file content.

I tried this, but all the content is in the same element:

$Getfile = Get-Content .\DeleteFile.txt
$TimeStamp = [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId(
        (Get-Date), 'Taipei Standard Time')
$delete_file = @"
<?xml version="1.0" encoding="UTF-8"?>
    <Handling>
        <Deleted>
            <1>$Getfile</1>
        </Deleted>
        <TimeStamp>$TimeStamp</TimeStamp>
    </Handling>
"@
$delete_file | Out-File .\DeleteFile.xml

Output:

<?xml version="1.0" encoding="UTF-8"?>
<Handling>
    <Deleted>
        <1>123asdf abdfeef 22343sf dfafdsf</1>
    </Deleted>
    <TimeStamp>12/04/2019 17:49:06</TimeStamp>
</Handling>

My expectation was that the output would be like this:

<?xml version="1.0" encoding="UTF-8"?>
<Handling>
    <Deleted>
        <1>123asdf</1>
        <2>abdfeef</2>
        <3>22343sf</3>
        <4>dfafdsf</4>
    </Deleted>
    <TimeStamp>12/04/2019 17:49:06</TimeStamp>
</Handling>

Can anyone help me please?

Upvotes: 1

Views: 677

Answers (2)

mklement0
mklement0

Reputation: 437753

vonPryz' helpful answer leverages the .NET XmlDocument API to construct the document.

A solution using an expandable string (string interpolation), as you've attempted, is possible, namely by including statements that enumerate the $Getfile array and construct numbered XML elements from its elements, via $(...), the sub-expression operator.

Two caveats:

  • XML element names must not start with a digit, so trying to create elements named 1, 2, ... will result in an invalid XML document. Therefore, the code below uses e1, e2, ... instead.

  • The code uses Set-Content -Encoding Utf8 to save the output file, so as to ensure that the character encoding used - UTF-8 - matches the encoding specified in the XML declaration (encoding="UTF-8").

    • At least in Windows PowerShell Out-File / > would result in UTF-16LE encoding instead.
      PowerShell [Core] v6+, however, consistently defaults to BOM-less UTF-8.
    • In Windows PowerShell, Set-Content -Encoding Utf8 creates a UTF-8 file with a BOM, unlike in PowerShell [Core] v6+. In Windows PowerShell, you cannot opt out of the BOM; in PowerShell [Core] v6+, you can opt in with -Encoding utf8BOM.
$Getfile = "123asdf", "abdfeef", "22343sf", "dfafdsf" # sample input

$delete_file = @"
<?xml version="1.0" encoding="UTF-8"?>
    <Handling>
        <Deleted>
$(
  $i = 0
  $(foreach ($el in $GetFile) {
    ++$i
"            <e$i>$el</e$i>"
  }) -join [Environment]::NewLine
)
        </Deleted>
        <TimeStamp>$TimeStamp</TimeStamp>
    </Handling>
"@

$delete_file | Set-Content -Encoding Utf8 .\DeleteFile.xml

Upvotes: 2

vonPryz
vonPryz

Reputation: 24071

The contents go into same element, as you are not creating new XML elements. To add elements, create a XML object and use its CreateElement and AppendChild methods. Like so,

# Skeleton document that is filled later
[xml]$d = @'
<Handling>
<Deleted />
<TimeStamp />
</Handling>
'@

# Dummy data, read these from a file instead    
$data = @('123asdf', 'abdfeef', '22343sf', 'dfafdsf')

# XPath selects the node under which new elements are added
$n = $d.SelectSingleNode('/Handling/Deleted')

# Loop through input data    
for($i=0; $i -lt $data.length; ++$i) {
    # Create new element, Element name is from loop counter
    $e = $d.CreateElement(($i+1).ToString())
    $e.InnerText = $data[$i]
    # Add the new node into document
    $n.AppendChild($e) | out-null
}
# Display the results.
$d.save([console]::out)

Output:

<?xml version="1.0" encoding="ibm850"?>
<Handling>
  <Deleted>
    <1>123asdf</1>
    <2>abdfeef</2>
    <3>22343sf</3>
    <4>dfafdsf</4>
  </Deleted>
  <TimeStamp />
</Handling>

Upvotes: 3

Related Questions