Variable being modified unintentionally by AppendChild

I have variable $purchaseOrdersTemplate outside of my foreach. When the line to AppendChild to the $purchaseOrder variable runs the item xml is being appended to both $purchaseOrder and $purchaseOrderTemplate. I would expect that it should not modify the template variable. Can I please get an explanation of this? For now I am putting the template variable in the first foreach so that it is reset each order but I think it looks weird to have it there.

foreach ($order in $groupOrders) {

  $purchaseOrder = $purchaseOrderTemplate
  $purchaseOrder.PurchaseOrderNew.InputParameter.PurchaseOrders.PurchaseOrder.OrderID = $order.Name

  foreach($orderItem in $order.Group) {
    $purchaseOrderItem = $purchaseOrderItemTemplate
    $purchaseOrderItem.PurchaseOrderItem.ItemOrderID = $orderItem.ItemArray[1]
    $purchaseOrderItem = $purchaseOrder.ImportNode($purchaseOrderItem.PurchaseOrderItem,$true)
    [void]$purchaseOrder.SelectSingleNode('/PurchaseOrderNew/InputParameter/PurchaseOrders/PurchaseOrder/PurchaseOrderItems').AppendChild($purchaseOrderItem)
  }
}

I don’t know if anyone here speaks fluently XML but I’d expect that some sample data may help understanding your issue and playing around to find a solution. :wink:

Of course :slight_smile:

[xml]$purchaseOrderTemplate =  @"
<PurchaseOrderNew>
    <InputParameter>
      <PurchaseOrders>
          <PurchaseOrder>
            <OrderId>PO</OrderId>
            <PurchaseOrderItems />
          </PurchaseOrder>
      </PurchaseOrders>
    </InputParameter>
</PurchaseOrderNew>
"@


[xml]$purchaseOrderItemTemplate = @"
<PurchaseOrderItem>
<ItemOrderID />
</PurchaseOrderItem>
"@

$groupOrders = $packageItems.Tables.Rows | Group-Object -Property OrderId

foreach ($order in $groupOrders) {

  $purchaseOrder = $purchaseOrderTemplate
  # $purchaseOrder.PurchaseOrderNew.InputParameter.PurchaseOrders.PurchaseOrder.OrderID = $order.Name

  foreach($orderItem in $order.Group) {
    write-host $orderItem.ItemArray
    $purchaseOrderItem = $purchaseOrderItemTemplate
    # $purchaseOrderItem.PurchaseOrderItem.ItemOrderID = $orderItem.ItemArray[1]
    $purchaseOrderItem = $purchaseOrder.ImportNode($purchaseOrderItem.PurchaseOrderItem,$true)
    [void]$purchaseOrder.SelectSingleNode('/PurchaseOrderNew/InputParameter/PurchaseOrders/PurchaseOrder/PurchaseOrderItems').AppendChild($purchaseOrderItem)
  }
}

I’m sorry but I don’t know how to provide sample data for $packageItems. It is a dataset. But, when I tried to create sample data using another format for posting the problem seemed to go away so maybe that helps to understand the problem.

[xml]$purchaseOrderTemplate =  @"
<PurchaseOrderNew>
    <InputParameter>
      <PurchaseOrders>
          <PurchaseOrder>
            <OrderId>PO</OrderId>
            <PurchaseOrderItems />
          </PurchaseOrder>
      </PurchaseOrders>
    </InputParameter>
</PurchaseOrderNew>
"@


[xml]$purchaseOrderItemTemplate = @"
<PurchaseOrderItem>
<ItemOrderID />
</PurchaseOrderItem>
"@

$orders = @"
OrderId,Customer,Item
4567,jsmith@company.org,Shoes 10.5
4570,tommy@anothercomp.com,Shirt XL
4567,jsmith@company.org,Shirt XL
4561,sally@company.org,Pants Small
4567,jsmith@company.org,Pant XL
"@ | ConvertFrom-Csv

$groupOrders = $orders | Group-Object -Property OrderId

foreach ($order in $groupOrders) {

  $purchaseOrder = $purchaseOrderTemplate
  # $purchaseOrder.PurchaseOrderNew.InputParameter.PurchaseOrders.PurchaseOrder.OrderID = $order.Name

  foreach($orderItem in $order.Group) {
    write-host $orderItem.ItemArray
    $purchaseOrderItem = $purchaseOrderItemTemplate
    # $purchaseOrderItem.PurchaseOrderItem.ItemOrderID = $orderItem.ItemArray[1]
    $purchaseOrderItem = $purchaseOrder.ImportNode($purchaseOrderItem.PurchaseOrderItem,$true)
    [void]$purchaseOrder.SelectSingleNode('/PurchaseOrderNew/InputParameter/PurchaseOrders/PurchaseOrder/PurchaseOrderItems').AppendChild($purchaseOrderItem)
  }
}

Sorry, I still did not get what you’re actually trying to do.

You could limit it to a few data sets and use Export-CliXML to export it into an XML formatted string. :wink:

So the problem might be caused by your input data.

Could you post a small sample of the expected result unsing your sample data?

I will post data Monday. The expectation is that the Template xml should not be getting modified. The code inserts the item xml node into the order xml which is what it should do, but it is also inserting it into the template xml so that the next time the template is used it has previous item nodes that should not be there.

… cool … I’m looking forward to it … :wink: :+1:t4:

Hope this is what you are looking for… The data comes from a parameterized query,

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>System.Data.SqlClient.SqlParameter</T>
      <T>System.Data.Common.DbParameter</T>
      <T>System.MarshalByRefObject</T>
      <T>System.Object</T>
    </TN>
    <ToString>@dateshipped</ToString>
    <Props>
      <Obj N="CompareInfo" RefId="1">
        <TN RefId="1">
          <T>System.Data.SqlTypes.SqlCompareOptions</T>
          <T>System.Enum</T>
          <T>System.ValueType</T>
          <T>System.Object</T>
        </TN>
        <ToString>None</ToString>
        <I32>0</I32>
      </Obj>
      <S N="XmlSchemaCollectionDatabase"></S>
      <S N="XmlSchemaCollectionOwningSchema"></S>
      <S N="XmlSchemaCollectionName"></S>
      <B N="ForceColumnEncryption">false</B>
      <Obj N="DbType" RefId="2">
        <TN RefId="2">
          <T>System.Data.DbType</T>
          <T>System.Enum</T>
          <T>System.ValueType</T>
          <T>System.Object</T>
        </TN>
        <ToString>DateTime</ToString>
        <I32>6</I32>
      </Obj>
      <I32 N="LocaleId">0</I32>
      <S N="ParameterName">@dateshipped</S>
      <By N="Precision">0</By>
      <By N="Scale">0</By>
      <Obj N="SqlDbType" RefId="3">
        <TN RefId="3">
          <T>System.Data.SqlDbType</T>
          <T>System.Enum</T>
          <T>System.ValueType</T>
          <T>System.Object</T>
        </TN>
        <ToString>DateTime</ToString>
        <I32>4</I32>
      </Obj>
      <Obj N="SqlValue" RefId="4">
        <TN RefId="4">
          <T>System.Data.SqlTypes.SqlDateTime</T>
          <T>System.ValueType</T>
          <T>System.Object</T>
        </TN>
        <ToString>11/3/2021 8:42:21 AM</ToString>
        <Props>
          <B N="IsNull">false</B>
          <DT N="Value">2021-11-03T08:42:21.42</DT>
          <I32 N="DayTicks">44501</I32>
          <I32 N="TimeTicks">9402426</I32>
        </Props>
      </Obj>
      <S N="UdtTypeName"></S>
      <S N="TypeName"></S>
      <DT N="Value">2021-11-03T08:42:21.42</DT>
      <Obj N="Direction" RefId="5">
        <TN RefId="5">
          <T>System.Data.ParameterDirection</T>
          <T>System.Enum</T>
          <T>System.ValueType</T>
          <T>System.Object</T>
        </TN>
        <ToString>Input</ToString>
        <I32>1</I32>
      </Obj>
      <B N="IsNullable">false</B>
      <I32 N="Offset">0</I32>
      <I32 N="Size">0</I32>
      <S N="SourceColumn"></S>
      <B N="SourceColumnNullMapping">false</B>
      <Obj N="SourceVersion" RefId="6">
        <TN RefId="6">
          <T>System.Data.DataRowVersion</T>
          <T>System.Enum</T>
          <T>System.ValueType</T>
          <T>System.Object</T>
        </TN>
        <ToString>Current</ToString>
        <I32>512</I32>
      </Obj>
    </Props>
  </Obj>
  <I32>3</I32>
  <Obj RefId="7">
    <TN RefId="7">
      <T>System.Data.DataSet</T>
      <T>System.ComponentModel.MarshalByValueComponent</T>
      <T>System.Object</T>
    </TN>
    <ToString>System.Data.DataSet</ToString>
    <Props>
      <Obj N="RemotingFormat" RefId="8">
        <TN RefId="8">
          <T>System.Data.SerializationFormat</T>
          <T>System.Enum</T>
          <T>System.ValueType</T>
          <T>System.Object</T>
        </TN>
        <ToString>Xml</ToString>
        <I32>0</I32>
      </Obj>
      <Obj N="SchemaSerializationMode" RefId="9">
        <TN RefId="9">
          <T>System.Data.SchemaSerializationMode</T>
          <T>System.Enum</T>
          <T>System.ValueType</T>
          <T>System.Object</T>
        </TN>
        <ToString>IncludeSchema</ToString>
        <I32>1</I32>
      </Obj>
      <B N="CaseSensitive">false</B>
      <Obj N="DefaultViewManager" RefId="10">
        <TN RefId="10">
          <T>System.Data.DataViewManager</T>
          <T>System.ComponentModel.MarshalByValueComponent</T>
          <T>System.Object</T>
        </TN>
        <LST>
          <Obj RefId="11">
            <TN RefId="11">
              <T>System.Data.DataViewManagerListItemTypeDescriptor</T>
              <T>System.Object</T>
            </TN>
            <ToString>System.Data.DataViewManagerListItemTypeDescriptor</ToString>
          </Obj>
        </LST>
      </Obj>
      <B N="EnforceConstraints">true</B>
      <S N="DataSetName">NewDataSet</S>
      <S N="Namespace"></S>
      <S N="Prefix"></S>
      <Obj N="ExtendedProperties" RefId="12">
        <TN RefId="12">
          <T>System.Data.PropertyCollection</T>
          <T>System.Collections.Hashtable</T>
          <T>System.Object</T>
        </TN>
        <DCT />
      </Obj>
      <B N="HasErrors">false</B>
      <B N="IsInitialized">true</B>
      <Obj N="Locale" RefId="13">
        <TN RefId="13">
          <T>System.Globalization.CultureInfo</T>
          <T>System.Object</T>
        </TN>
        <ToString>en-US</ToString>
        <Props>
          <I32 N="LCID">1033</I32>
          <S N="Name">en-US</S>
          <S N="DisplayName">English (United States)</S>
          <S N="IetfLanguageTag">en-US</S>
          <S N="ThreeLetterISOLanguageName">eng</S>
          <S N="ThreeLetterWindowsLanguageName">ENU</S>
          <S N="TwoLetterISOLanguageName">en</S>
        </Props>
      </Obj>
      <Nil N="Site" />
      <Obj N="Relations" RefId="14">
        <TN RefId="14">
          <T>System.Data.DataRelationCollection+DataSetRelationCollection</T>
          <T>System.Data.DataRelationCollection</T>
          <T>System.Data.InternalDataCollectionBase</T>
          <T>System.Object</T>
        </TN>
        <IE />
        <Props>
          <I32 N="Count">0</I32>
          <B N="IsReadOnly">false</B>
          <B N="IsSynchronized">false</B>
          <Ref N="SyncRoot" RefId="14" />
        </Props>
      </Obj>
      <Obj N="Tables" RefId="15">
        <TN RefId="15">
          <T>System.Data.DataTableCollection</T>
          <T>System.Data.InternalDataCollectionBase</T>
          <T>System.Object</T>
        </TN>
        <IE>
          <Obj RefId="16">
            <TN RefId="16">
              <T>System.Data.DataTable</T>
              <T>System.ComponentModel.MarshalByValueComponent</T>
              <T>System.Object</T>
            </TN>
            <IE>
              <Obj RefId="17">
                <TN RefId="17">
                  <T>System.Data.DataRow</T>
                  <T>System.Object</T>
                </TN>
                <ToString>System.Data.DataRow</ToString>
                <Props>
                  <I32 N="ID">4</I32>
                  <S N="OrderNumber">1548</S>
                  <S N="TrackingNo">456</S>
                  <DT N="DateShipped">2021-11-04T00:00:00</DT>
                  <Db N="Weight">6</Db>
                  <D N="Cost">5.5000</D>
                  <S N="AccountNumber"></S>
                  <S N="ServiceType">GRND</S>
                  <S N="Carrier">ACME</S>
                  <I64 N="OrderId">399</I64>
                  <B N="processed">false</B>
                </Props>
              </Obj>
              <Obj RefId="18">
                <TNRef RefId="17" />
                <ToString>System.Data.DataRow</ToString>
                <Props>
                  <I32 N="ID">5</I32>
                  <S N="OrderNumber">1547</S>
                  <S N="TrackingNo">456</S>
                  <DT N="DateShipped">2021-11-04T00:00:00</DT>
                  <Db N="Weight">6</Db>
                  <D N="Cost">5.5000</D>
                  <S N="AccountNumber"></S>
                  <S N="ServiceType">GRND</S>
                  <S N="Carrier">ACME</S>
                  <I64 N="OrderId">398</I64>
                  <B N="processed">false</B>
                </Props>
              </Obj>
              <Obj RefId="19">
                <TNRef RefId="17" />
                <ToString>System.Data.DataRow</ToString>
                <Props>
                  <I32 N="ID">6</I32>
                  <S N="OrderNumber">1547</S>
                  <S N="TrackingNo">456</S>
                  <DT N="DateShipped">2021-11-04T00:00:00</DT>
                  <Db N="Weight">6</Db>
                  <D N="Cost">5.5000</D>
                  <S N="AccountNumber"></S>
                  <S N="ServiceType">GRND</S>
                  <S N="Carrier">ACME</S>
                  <I64 N="OrderId">398</I64>
                  <B N="processed">false</B>
                </Props>
              </Obj>
            </IE>
            <Props>
              <B N="CaseSensitive">false</B>
              <B N="IsInitialized">true</B>
              <S N="RemotingFormat">Xml</S>
              <Obj N="ChildRelations" RefId="20">
                <TN RefId="18">
                  <T>System.Data.DataRelationCollection+DataTableRelationCollection</T>
                  <T>System.Data.DataRelationCollection</T>
                  <T>System.Data.InternalDataCollectionBase</T>
                  <T>System.Object</T>
                </TN>
                <IE />
              </Obj>
              <Obj N="Columns" RefId="21">
                <TN RefId="19">
                  <T>System.Data.DataColumnCollection</T>
                  <T>System.Data.InternalDataCollectionBase</T>
                  <T>System.Object</T>
                </TN>
                <IE>
                  <S>ID</S>
                  <S>OrderNumber</S>
                  <S>TrackingNo</S>
                  <S>DateShipped</S>
                  <S>Weight</S>
                  <S>Cost</S>
                  <S>AccountNumber</S>
                  <S>ServiceType</S>
                  <S>Carrier</S>
                  <S>OrderId</S>
                  <S>processed</S>
                </IE>
              </Obj>
              <Obj N="Constraints" RefId="22">
                <TN RefId="20">
                  <T>System.Data.ConstraintCollection</T>
                  <T>System.Data.InternalDataCollectionBase</T>
                  <T>System.Object</T>
                </TN>
                <IE />
              </Obj>
              <S N="DataSet">System.Data.DataSet</S>
              <Obj N="DefaultView" RefId="23">
                <TN RefId="21">
                  <T>System.Data.DataView</T>
                  <T>System.ComponentModel.MarshalByValueComponent</T>
                  <T>System.Object</T>
                </TN>
                <LST>
                  <S>System.Data.DataRowView</S>
                  <S>System.Data.DataRowView</S>
                  <S>System.Data.DataRowView</S>
                </LST>
              </Obj>
              <S N="DisplayExpression"></S>
              <Obj N="ExtendedProperties" RefId="24">
                <TNRef RefId="12" />
                <DCT />
              </Obj>
              <B N="HasErrors">false</B>
              <Ref N="Locale" RefId="13" />
              <I32 N="MinimumCapacity">50</I32>
              <Obj N="ParentRelations" RefId="25">
                <TNRef RefId="18" />
                <IE />
              </Obj>
              <Obj N="PrimaryKey" RefId="26">
                <TN RefId="22">
                  <T>System.Data.DataColumn[]</T>
                  <T>System.Array</T>
                  <T>System.Object</T>
                </TN>
                <LST />
              </Obj>
              <Obj N="Rows" RefId="27">
                <TN RefId="23">
                  <T>System.Data.DataRowCollection</T>
                  <T>System.Data.InternalDataCollectionBase</T>
                  <T>System.Object</T>
                </TN>
                <IE>
                  <Ref RefId="17" />
                  <Ref RefId="18" />
                  <Ref RefId="19" />
                </IE>
              </Obj>
              <S N="TableName">Table</S>
              <S N="Namespace"></S>
              <S N="Prefix"></S>
              <Nil N="Site" />
              <Nil N="Container" />
              <B N="DesignMode">false</B>
              <B N="ContainsListCollection">false</B>
            </Props>
          </Obj>
        </IE>
        <Props>
          <I32 N="Count">1</I32>
          <B N="IsReadOnly">false</B>
          <B N="IsSynchronized">false</B>
          <Ref N="SyncRoot" RefId="15" />
        </Props>
      </Obj>
      <Nil N="Container" />
      <B N="DesignMode">false</B>
      <B N="ContainsListCollection">true</B>
    </Props>
  </Obj>
</Objs>

When you execute this command

$purchaseOrder = $purchaseOrderTemplate

You are linking these objects. $purchaseOrder is just a reference to the template, not a copy. You should clone it instead

$purchaseOrder = $purchaseOrderTemplate.Clone()

Now when you modify $purchaseOrder it won’t affect the template.

Great, thank you krzydoug. And thank you as well, Olaf.