Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.3k views
in Technique[技术] by (71.8m points)

Add Line To XML File With Powershell

Apologies in advance as I have a very basic knowledge of Powershell, and even less knowledge of XML. But I have an XML file that I need to add a line to, and I'm trying to figure out how to do it with Powershell (because in the end, I'm going to have to do this a few thousand times). So file.xml is formatted as such:

<?xml version="1.0" encoding="utf-8"?>
<Sources>
  <add id="Source1" type="Test" distance="1">
    <parameters>
      <name />
      <address />
      <otherIdentifiers>FirstSource</otherIdentifiers>
      <supportedQueryTypes>Document</supportedQueryTypes>
      <host>10.5.19.194</host>
      <port>192</port>
    </parameters>
  </add>
  <add id="Source2" type="Prod" distance="2">
    <parameters>
      <name />
      <address />
      <otherIdentifiers>SecondSource</otherIdentifiers>
      <supportedQueryTypes>Document</supportedQueryTypes>
      <host>10.5.19.195</host>
      <port>193</port>
      <prod.baseUrl>http://SOURCE2PRODURL/Page</prod.baseUrl>
      <cache.enablePrefetch>false</cache.enablePrefetch>
    </parameters>
  </add>
  <add id="Source3" type="Prod" distance="3">
    <parameters>
      <name />
      <address />
      <otherIdentifiers>ThirdSource</otherIdentifiers>
      <supportedQueryTypes>Document</supportedQueryTypes>
      <host>10.5.19.197</host>
      <port>194</port>
      <prod.baseUrl>http://SOURCE3PRODURL/Page</prod.baseUrl>
      <cache.enablePrefetch>true</cache.enablePrefetch>
    </parameters>
  </add>
</Sources>

My goal is to find any source where type="Prod" and add the following line AFTER the prod.baseURL line:

<timeout>500</timeout>

So in the end, the section for Source2 and Source3 should essentially be formatted as:

  <add id="Source2" type="Prod" distance="2">
    <parameters>
      <name />
      <address />
      <otherIdentifiers>SecondSource</otherIdentifiers>
      <supportedQueryTypes>Document</supportedQueryTypes>
      <host>10.5.19.195</host>
      <port>193</port>
      <prod.baseUrl>http://SOURCE2PRODURL/Page</prod.baseUrl>
      <timeout>500</timeout>
      <cache.enablePrefetch>false</cache.enablePrefetch>
    </parameters>
  </add>
  <add id="Source3" type="Prod" distance="3">
    <parameters>
      <name />
      <address />
      <otherIdentifiers>ThirdSource</otherIdentifiers>
      <supportedQueryTypes>Document</supportedQueryTypes>
      <host>10.5.19.197</host>
      <port>194</port>
      <prod.baseUrl>http://SOURCE3PRODURL/Page</prod.baseUrl>
      <timeout>500</timeout>
      <cache.enablePrefetch>true</cache.enablePrefetch>
    </parameters>
  </add>

So this is what I've tried. If it makes absolutely no sense, I apologize, as it makes absolutely no sense to me...

$Path = .File.xml

[XML]$File = Get-Content -Path $Path -Raw

    $Sources = $File.Sources.add | Where-Object type -EQ "Prod"
    $URL = $Sources.parameters.{prod.baseurl}

    $Timeout = [XML]"@
        <add name='timeout' value='500'/>
        @"

    Foreach($Source in $Sources){
        $Timeout.InsertAfter($File.ImportNode($Timeout.parameters, $true), $URL)
        }
    $File.Save($Path)

And in the end, I'm getting:

Cannot convert value "@
        <add name='timeout' value='500'/>
        @" to type "System.Xml.XmlDocument". Error: "The specified node cannot be inserted as the valid child of this node, because the specified node is the 
wrong type."

I realize this is ugly and totally wrong, but can anyone point me in the right direction?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The problem is, when you use the easy dot notation for accessing XML elements, in some cases PowerShell converts these elements to other, simpler data types. In your case it converts prod.baseUrl element to String, because it contains only string content.

This is a problem as XmlElement.InsertAfter() requires arguments of type XmlNode, not String.

The solution uses XPath instead:

# Select child elements using XPath expression
$parameters = $File.SelectNodes("/Sources/add[@type='Prod']/parameters")

# For all found child elements
foreach( $param in $parameters ) {

    # Create timeout element 
    $timeout = $File.CreateElement('timeout')
    $timeout.InnerText = '500'

    # Insert timeout element after 'prod.baseUrl' element
    $param.InsertAfter( $timeout, $param.SelectSingleNode('prod.baseUrl') ) 
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...