none
Copy XML Node From One File And Append It To Another XML File RRS feed

  • Question

  • Hi ALL,

    Need Help On Powershell Script For Copy XML Node From One File And Append It To Another XML File.

    Objective : We have xml files with same node structure.However, everytime source is updated with certain value 
                       it has to be updated manually into target xml node. We would to automate this one where whenever source
                file is updated anyone from team will let the automation guy know about it and then automation guy will execute                      this script to update the target xml node with laest value.


    Current Situation Is A. Success : Current Powershell Script is able to read the source xml node and also able to 
                                          delete target node and then append the target xml with source xml node value.

            B. Failure or Error : Exception calling "ImportNode" with "2" argument(s): "Cannot import a null node."
                                                  At E:\Carbon\xmlreplacenode-1.ps1:51 char:1
                                                  + [void] $parent.AppendChild($servicefactoryconfig.ImportNode($newNode. ...
                                                  + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                  + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
                                                  + FullyQualifiedErrorId : DotNetMethodException



    Powershell Script : 



    #################### Get Source XML <Section Name="APILibraries"> Node Value ##########################

    $CustomWinClientConfigXmlSource = "SourcePath\Config.xml"

    [xml]$SourceConfigXml = Get-Content -Path "$CustomWinClientConfigXmlSource" -Raw
    $SourceXmlNode = $SourceConfigXml | Select-Xml -XPath "//Section[@Name='APILibraries']"
    $SourceXmlOutput = Write-Output "$SourceXmlNode"
    $SourceXMLNodeValue = "$SourceXmlOutput"




    #################### Get The Target XML <Section Name="APILibraries"> Node Value And Delete It ##############

    $WinClientConfigFiles = "Config.xml"
    $CustomWinClientConfigXmlTarget = "TargetPath\$WinClientConfigFiles"

    $Path = "$CustomWinClientConfigXmlTarget"

    [Xml]$servicefactoryconfig = Get-Content -Path $Path -Raw

    $old = $servicefactoryconfig.SelectSingleNode("/Configuration/Data/Section[@Name='APILibraries']")

    $parent = $old.ParentNode

    [void] $parent.RemoveChild($old)


    ################################# Append The Target XML <Section Name="APILibraries"> With Source XML Node Value ###########

    Try

    {

    $newNode = [Xml] @"
    $SourceXMLNodeValue
    "@

    }

    Catch

    {

    Write-Error -Message 'Ignoring The Error Message' -ErrorAction Ignore

    }

    [void] $parent.AppendChild($servicefactoryconfig.ImportNode($newNode.DocumentElement,$true))

    $servicefactoryconfig.save($path)

    XML Source & Target : Node Name is APILibaries which is  <Section Name="APILibraries"> <Item Name=/> </Section>

    Source XML File Looks          

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
    <Data>

         <Section Name="Settings">
          <Item Name=/>
          <Item Name=/>
          <Item Name=/>
          <Item Name=/>

          <Item Name=/>

           <Item Name=/>
        </Section>

    <Section Name="APILibraries">
    <Item Name=/>

    </Section>
    </Section>
    </Data>
    </Configuration>

    Target XML Node Looks : 

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
    <Data>

         <Section Name="Settings">
          <Item Name=/>
          <Item Name=/>
          <Item Name=/>
          <Item Name=/>

          <Item Name=/>

           <Item Name=/>
        </Section>

    <Section Name="APILibraries">
    <Item Name=/>

    </Section>
    </Section>
    </Data>
    </Configuration>

      
    • Moved by Bill_Stewart Tuesday, July 10, 2018 7:58 PM This is not "scripts on demand"
    Friday, May 25, 2018 3:16 PM

All replies

  • Please post your code correctly using the code posting tool provided on the edit toolbar.

    \_(ツ)_/

    Friday, May 25, 2018 3:22 PM
  • ##### Section A #########
    ##### Get Source XML <Section Name="APILibraries"> Node Value ##########################
    
    $CustomWinClientConfigXmlSource = "SourcePath\Config.xml"
    
    [xml]$SourceConfigXml = Get-Content -Path "$CustomWinClientConfigXmlSource" -Raw
    $SourceXmlNode = $SourceConfigXml | Select-Xml -XPath "//Section[@Name='APILibraries']"
    $SourceXmlOutput = Write-Output "$SourceXmlNode"
    $SourceXMLNodeValue = "$SourceXmlOutput"
    
    
    
    ##### Section B #########
    ##### Get The Target XML <Section Name="APILibraries"> Node Value And Delete It #######
    
    $WinClientConfigFiles = "Config.xml"
    $CustomWinClientConfigXmlTarget = "TargetPath\$WinClientConfigFiles"
    
    $Path = "$CustomWinClientConfigXmlTarget"
    
    [Xml]$servicefactoryconfig = Get-Content -Path $Path -Raw
    
    $old = $servicefactoryconfig.SelectSingleNode("/Configuration/Data/Section[@Name='APILibraries']")
    
    $parent = $old.ParentNode
    
    [void] $parent.RemoveChild($old)
    
    
    ##### Section C #########
    ##### Append The Target XML <Section Name="APILibraries"> With Source XML Node Value ###########
    
    Try
    
    {
    
    $newNode = [Xml] @"
    $SourceXMLNodeValue
    "@
    
    }
    
    Catch
    
    {
    
    Write-Error -Message 'Ignoring The Error Message' -ErrorAction Ignore
    
    }
    
    [void] $parent.AppendChild($servicefactoryconfig.ImportNode($newNode.DocumentElement,$true))
    
    $servicefactoryconfig.save($path)
    

    Hi,

    Here is powershell code. Section A is working fine , it is able to read the node value in holding it in "SourceXMLNodeValue" variable. Similarley , for Section B it is able to get the value and delete the required node. However , in Section C, when i am trying to append the "newNode" variable value it is throwing the Empty string , in fact i am using ""SourceXMLNodeValue" varible value there. I am not quite sure about wheather i am using correct syntax or not.

    If required i can also paste the XML syntax again. However, i have already posted in my previous post.

    Thanks

    Vivek

    Monday, May 28, 2018 6:55 AM
  • You cannot paste XML between file.  You must use the primitives to recompile the XML is the target document.

    If you would correctly format you code and XML and post correctly I could probable see your mistakes.

    XML and code can be posted with the code posting tool.  Code should be correctly formatted and indented for readability.


    \_(ツ)_/


    • Edited by jrv Monday, May 28, 2018 1:27 PM
    Monday, May 28, 2018 1:26 PM
  • Hi,

    I have re uploaded the code. Probably this it would give some infor to help me out. Also i am separately posting code for xml files following powesrshell code.

    SOURCE XML FILE LOOKS :

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
       <Data>
          <Section Name="Settings">
              <Item Name=/>
              <Item Name=/>
              <Item Name=/>
              <Item Name=/>
               <Item Name=/>
               <Item Name=/>
        </Section>
    	
         <Section Name="APILibraries">
             <Item Name=Item A/>
             <Item Name=Item B/>
              <Item Name=Item C/>
         </Section>
    
          </Section>
       </Data>
    </Configuration>

    TARGET XML NODE LOOKS : 

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
       <Data>
         <Section Name="Settings">
          <Item Name=/>
          <Item Name=/>
          <Item Name=/>
          <Item Name=/>
          <Item Name=/>
           <Item Name=/>
        </Section>
    
       <Section Name="APILibraries">
           <Item Name=Item 1/>
           <Item Name=Item 2/>
            <Item Name=Item 3/>
       </Section>
    </Data>
    </Configuration>


    New Powershell Code  :

    ## Section A ##
    ##### Get Source XML <Section Name="APILibraries"> Node Value ##
    
    $CustomWinClientConfigXmlSource = "SourcePath\Config.xml"
    
    [xml]$SourceConfigXml = Get-Content -Path "$CustomWinClientConfigXmlSource" -Raw
    $SourceXmlNode = $SourceConfigXml | Select-Xml -XPath "//Section[@Name='APILibraries']"
    $SourceXmlOutput = Write-Output "$SourceXmlNode"
    $SourceXMLNodeValue = "$SourceXmlOutput"
    
    
    
    ## Section B ## Get The Target XML <Section Name="APILibraries"> Node Value And Delete It ##
    
    $WinClientConfigFiles = "Config.xml"
    $CustomWinClientConfigXmlTarget = "TargetPath\$WinClientConfigFiles"
    
    $Path = "$CustomWinClientConfigXmlTarget"
    
    [Xml]$servicefactoryconfig = Get-Content -Path $Path -Raw
    
    $old = $servicefactoryconfig.SelectSingleNode("/Configuration/Data/Section[@Name='APILibraries']")
    
    $parent = $old.ParentNode
    
    [void] $parent.RemoveChild($old)
    
    [void] $parent.AppendChild($servicefactoryconfig.ImportNode($SourceXMLNodeValue.DocumentElement,$true))
    
    $servicefactoryconfig.save($path)

    Do let me know if anything else required to help me out.

    Thanks

    Vivek

    Monday, May 28, 2018 2:42 PM
  • Your XML is broken.  You cannot do this:

    <Item Name=/>

    An attribute must have a value.


    \_(ツ)_/

    Monday, May 28, 2018 2:55 PM
  • You cannot do this:

    <Item Name=Item 1/>
    <Item Name=Item 2/>

    Attribute values must be quoted.


    \_(ツ)_/

    Monday, May 28, 2018 2:56 PM
  • Both of your XML samples are badly broken for multiple reasons.


    \_(ツ)_/

    Monday, May 28, 2018 3:00 PM
  • Hi,

    Please suggest how can i copy the source "Section" node and before modify target xml need to delete to delete same node and append with source copied node.

    SOURCE XML : 

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
       <Data>
         <Section Name="APILibraries">
    			<Item Name="TIMSS.API.UserSFAPERSONIFY" Layer="User" Type="Custom" RootNamespace="TIMSS.API.UserSFAPERSONIFY" FileName="TIMSS.API.UserSFAPERSONIFY.dll" />
    			<Item Name="TIMSS.API.User.Generated" Layer="User" Type="Generated" RootNamespace="TIMSS.API.User" FileName="Personify.API.User.Generated.dll" />
    			<Item Name="TIMSS.API.Base" Layer="Base" Type="Custom" RootNamespace="TIMSS.API.Base" FileName="TIMSS.API.Base.dll" />
    			<Item Name="TIMSS.API.Generated" Layer="Base" Type="Generated" RootNamespace="TIMSS.API.Generated" FileName="TIMSS.API.Generated.dll" />
    			<Item Name="TIMSS.API.Core" Layer="Core" Type="Custom" RootNamespace="TIMSS.API.Core" FileName="TIMSS.API.Core.dll" />
    		</Section>
    </Data>
    </Configuration>

    TARGET XML  : 

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
    <Data> 
          <Section Name="APILibraries">
    	         <Item Name="TIMSS.API.Generated" Layer="Custom" Type="Generated" RootNamespace="TIMSS.API.Generated" FileName="TIMSS.API.Generated.dll" />
    			<Item Name="TIMSS.API.Generated" Layer="Base" Type="Generated" RootNamespace="TIMSS.API.Generated" FileName="TIMSS.API.Generated.dll" />
    			<Item Name="TIMSS.API.Core" Layer="Core" Type="Custom" RootNamespace="TIMSS.API.Core" FileName="TIMSS.API.Core.dll" />
    		</Section>
    </Data>
    </Configuration>

    I hope this time you, it should give sufficient info to understand the power shell script.Do lemme know what else i can provide.

    Thanks

    Vivek


    Monday, May 28, 2018 3:04 PM
  • Here is an example.  Try to not com plicate your code with so many comments and unnecessary lines.

    [xml]$SourceConfigXml = @'
    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
        <Data>
            <Section Name="Settings">
                <Item Name="A"/>
                <Item Name="B"/>
                <Item Name="C"/>
                <Item Name="D"/>
                <Item Name="E"/>
                <Item Name="F"/>
            </Section>
            <Section Name="APILibraries">
                <Item Name="Item A"/>
                <Item Name="Item B"/>
                <Item Name="Item C"/>
            </Section>
       </Data>
    </Configuration>
    '@
    
    
    [Xml]$servicefactoryconfig = @'
    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
        <Data>
            <Section Name="Settings">
                <Item Name="1"/>
                <Item Name="2"/>
                <Item Name="3"/>
                <Item Name="4"/>
                <Item Name="5"/>
                <Item Name="6"/>
            </Section>
            <Section Name="APILibraries">
                <Item Name="Item 1"/>
                <Item Name="Item 2"/>
                <Item Name="Item 3"/>
            </Section>
        </Data>
    </Configuration>
    '@
    
    $sourceNode = $sourceXml.SelectSingleNode('//Section[@Name="APILibraries"]')
    $old = $servicefactoryconfig.SelectSingleNode('//Configuration/Data/Section[@Name="APILibraries"]')
    $old.ParentNode.RemoveChild($old)
    $servicefactoryconfig.SelectSingleNode('//Data')
    $newnode = $servicefactoryconfig.ImportNode($sourceNode,$true)
    $dataNode.AppendChild($newNode)
    


    \_(ツ)_/

    • Proposed as answer by jrv Tuesday, May 29, 2018 7:35 AM
    Monday, May 28, 2018 3:12 PM
  • Hi,

    I have tried that way and it is working for me if i put manually the those value's or as you have wrote the script.

    However, the objective of this powershell script is to copy a node from share location automatically and paster in another xml. Above code involves manually entry of node list.If you see my earlier code , i am trying to read the 

    node file from some path location and then append it. If you can help me to automate for reading the node value from source xml and then delete by following append with source node. In this whole process the only thing 

    i need to modify is source and target file location through variable.

    I am sure you will help me with this.

    Thanks

    Vivek

    Monday, May 28, 2018 3:26 PM
  • So use Get-Content.

    [Xml]$servicefactoryconfig = Get-Content $file


    \_(ツ)_/

    Monday, May 28, 2018 3:40 PM
  • hi ,

    I am using that one to get the value from file which on shared location and it is working fine.

    Even though if i am using that one than still how i would use them in code to append the value.

    For your reference, i have bit modify the code to just do some workaround.

    #################### Get Source XML <Section Name="APILibraries"> Node Value ##########################
    
    $CustomWinClientConfigXmlSource = "\\10.131.50.89\Personify\VIV762DEV\Win Client\THA762DEV\Config\Config.xml"
    
    [xml]$SourceConfigXml = Get-Content -Path "$CustomWinClientConfigXmlSource" -Raw
    $SourceXmlNode = $SourceConfigXml | Select-Xml -XPath "//Section[@Name='APILibraries']"
    $SourceXmlOutput = Write-Output "$SourceXmlNode"
    $SourceXMLNodeValue = "$SourceXmlOutput"
    
    
    
    
    #################### Get The Target XML <Section Name="APILibraries"> Node Value And Delete It ##############
    
    $WinClientConfigFiles = "Config-B.xml"
    $CustomWinClientConfigXmlTarget = "C:\Users\vivek.singh2\Desktop\$WinClientConfigFiles"
    
    $Path = "$CustomWinClientConfigXmlTarget"
    
    [Xml]$servicefactoryconfig = Get-Content -Path $Path -Raw
    
    $old = $servicefactoryconfig.SelectSingleNode("/Configuration/Data/Section[@Name='APILibraries']")
    
    $parent = $old.ParentNode
    
    [void] $parent.RemoveChild($old)
    
    
    ################################# Append The Target XML <Section Name="APILibraries"> With Source XML Node Value ###########
    
    
    [void] $parent.AppendChild($servicefactoryconfig.ImportNode($SourceXMLNodeValue.DocumentElement,$true))
    
    $servicefactoryconfig.save($path)

    Config.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
       <Data>
         <Section Name="APILibraries">
    			<Item Name="TIMSS.API.User" Layer="User" Type="Custom" RootNamespace="TIMSS.API.User" FileName="TIMSS.API.User.dll" />
    			<Item Name="TIMSS.API.User.Generated" Layer="User" Type="Generated" RootNamespace="TIMSS.API.User" FileName="Personify.API.User.Generated.dll" />
    			<Item Name="TIMSS.API.Base" Layer="Base" Type="Custom" RootNamespace="TIMSS.API.Base" FileName="TIMSS.API.Base.dll" />
    			<Item Name="TIMSS.API.Generated" Layer="Base" Type="Generated" RootNamespace="TIMSS.API.Generated" FileName="TIMSS.API.Generated.dll" />
    			<Item Name="TIMSS.API.Core" Layer="Core" Type="Custom" RootNamespace="TIMSS.API.Core" FileName="TIMSS.API.Core.dll" />
    		</Section>
    </Data>
    </Configuration>

    Config-B.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <Configuration>
       <Data>
         <Section Name="APILibraries">
    			<Item Name="TIMSS.API.Base" Layer="Base" Type="Custom" RootNamespace="TIMSS.API.Base" FileName="TIMSS.API.Base.dll" />
    			<Item Name="TIMSS.API.Generated" Layer="Base" Type="Generated" RootNamespace="TIMSS.API.Generated" FileName="TIMSS.API.Generated.dll" />
    			<Item Name="TIMSS.API.Core" Layer="Core" Type="Custom" RootNamespace="TIMSS.API.Core" FileName="TIMSS.API.Core.dll" />
    		</Section>
    </Data>
    </Configuration>

     
    Tuesday, May 29, 2018 7:00 AM