XML: Updating an existing file

Does anyone have a sample of how to update an existing XML file. I am not talking about adding a node to an xml file that is already open and not finished. I mean that a file that has been written to, closed, and reopened to add more nodes. I am not savy with writing xml files.

Here is my situation. We have a company that wants to utilize a cXML format to pass information to them, via a portal on their end, to inform them when a shipment is coming. I am commissioning the UD01 table and UI for this information. I push out to UD01 information from the Customer Shipment screen.

The file is designed to contain a node for each line of a PO (their POs) that is being shipped. My code is below. I am stuck in the UpdateASNFile method. if you look below you will see. Can you help!! All takers are welcome.

private bool ProcessSubmissions(ref string sErrorMessage)
{
	bool bRet = true;
	bool bSubmitCheck = false;
	bool bAllGood = false;
	sErrorMessage = string.Empty;
	string sCurrentPO = string.Empty;
	string sLastPO = string.Empty;

	
	try
	{//sASNFileText is the string to create the xml nodes
		foreach(DataRowView dr in this.edvUD01.dataView)
		{
			sCurrentPO = dr["Key4"].ToString();
			bSubmitCheck = Convert.ToBoolean(dr["CheckBox01"]);
			
			if(bSubmitCheck == true)
			{
				if(sCurrentPO != sLastPO)
				{
					bAllGood = CreateASNFile(dr);
					sLastPO = sCurrentPO;
				}
				else
				{//Update xml file with POLine data
					bAllGood = UpdateASNFile(dr);
				}
				if(bAllGood == true)
				{
					dr.BeginEdit();
					dr["CheckBox02"] = true;
					dr.EndEdit();
					oTrans.Update();
					dr.BeginEdit();
					dr["RowMod"] = "D";
					dr.EndEdit();
					//oTrans.Delete();
				}
			
			}
		}
	}
	catch(Exception ex)
	{
		sErrorMessage = ex.Message;
		bRet = false;
	}

	return bRet;
}
private bool CreateASNFile(DataRowView myDR)
{
    bool bResults = false;
	XmlWriter xmlWriter = null;
    try
    {
        if(bASNWritePermission)
        {//DateTime.Now.TimeOfDay
			DateTime dtNow = DateTime.Now;
			string sDateString =  dtNow.Year.ToString() + "-" + dtNow.Month.ToString() + "-"  + dtNow.Day.ToString();
			string sDateTimeString = dtNow.Year.ToString() + dtNow.Month.ToString() + dtNow.Day.ToString() + "T" + dtNow.Hour + ":" + dtNow.Minute + ":" + dtNow.Second;
	
			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;
			settings.OmitXmlDeclaration = false;
			settings.NewLineOnAttributes = false;

            string sFileName = "\\EMF_" + dtNow.Year + dtNow.Month + dtNow.Day + "_PO" + myDR["Key4"].ToString() + ".xml";
            string sPath = sASNFolder; 
			string sArchive = sASNArchiveFolder;  

            sPath += sFileName;
			sArchive += sFileName;

            if(File.Exists(sPath) == false)
            {//lineNumber
				xmlWriter = XmlWriter.Create(sPath, settings);
				xmlWriter.WriteStartDocument();
				xmlWriter.WriteDocType("cXML", null, @"http://xml.cXML.org/schemas/cXML/1.2.041/Fulfill.dtd", "");
				xmlWriter.WriteStartElement("cXML");
				xmlWriter.WriteAttributeString("timestamp", sDateTimeString); 
				xmlWriter.WriteAttributeString("payloadID", sDateTimeString + "PO." + myDR["Key4"].ToString() ); 
				//xmlWriter.WriteAttributeString("version", "1.2.041" ); 
				xmlWriter.WriteComment(" Elite Metal Finishing LLC ASN File ");
					//Header
					xmlWriter.WriteStartElement("Header");
						xmlWriter.WriteStartElement("From");
							xmlWriter.WriteStartElement("Credential");
								xmlWriter.WriteAttributeString("domain", string.Empty);
								xmlWriter.WriteStartElement("Identity");
								xmlWriter.WriteEndElement();//Identity
							xmlWriter.WriteEndElement();//Credential
						xmlWriter.WriteEndElement();//From
						xmlWriter.WriteStartElement("To");
							xmlWriter.WriteStartElement("Credential");
								xmlWriter.WriteAttributeString("domain", string.Empty);
								xmlWriter.WriteStartElement("Identity");
								xmlWriter.WriteEndElement();
							xmlWriter.WriteEndElement();
						xmlWriter.WriteEndElement();//To
						xmlWriter.WriteStartElement("Sender");
							xmlWriter.WriteStartElement("Credential");
								xmlWriter.WriteAttributeString("domain", string.Empty);
								xmlWriter.WriteStartElement("Identity");
								xmlWriter.WriteEndElement();
								xmlWriter.WriteStartElement("SharedSecret");
								xmlWriter.WriteEndElement();
							xmlWriter.WriteEndElement();
							xmlWriter.WriteStartElement("UserAgent");
							xmlWriter.WriteEndElement();
						xmlWriter.WriteEndElement();//Sender
					xmlWriter.WriteEndElement();//Header
					//Request Node
					xmlWriter.WriteStartElement("Request");
						xmlWriter.WriteAttributeString("deploymentMode", "production");
						xmlWriter.WriteStartElement("ShipNoticeRequest");
						//Inside of this node is the meat
							xmlWriter.WriteStartElement("ShipNoticeHeader");
								xmlWriter.WriteAttributeString("shipmentID", myDR["Key2"].ToString());
								xmlWriter.WriteAttributeString("operation", "new");
								xmlWriter.WriteAttributeString("noticeDate", sDateString);
								xmlWriter.WriteAttributeString("shipmentDate", sDateString);
								//xmlWriter.WriteAttributeString("deliveryDate", PackID);

								xmlWriter.WriteStartElement("ServiceLevel");
								//xmlWriter.WriteAttributeString("xml:lang", "en");
								xmlWriter.WriteValue("SameDay");
								xmlWriter.WriteEndElement();//ServiceLevel

								xmlWriter.WriteStartElement("Packaging");
								xmlWriter.WriteValue("See original PO for details");
								xmlWriter.WriteEndElement();//Packaging
							xmlWriter.WriteEndElement();//ShipNoticeHeader

							xmlWriter.WriteStartElement("ShipControl");
								xmlWriter.WriteStartElement("CarrierIdentifier");
								xmlWriter.WriteAttributeString("domain", "company name");
								xmlWriter.WriteValue(myDR["ShortChar06"].ToString());
								xmlWriter.WriteEndElement();//CarrierIdentifier::Carrier name

								if(string.IsNullOrEmpty(myDR["ShortChar07"].ToString()) == false)
								{		
									xmlWriter.WriteStartElement("CarrierIdentifier");
									xmlWriter.WriteAttributeString("domain", "SCAC");
									xmlWriter.WriteValue(myDR["ShortChar07"].ToString());
									xmlWriter.WriteEndElement();//CarrierIdentifier::SCAC
								}

								xmlWriter.WriteStartElement("ShipmentIdentifier");
								xmlWriter.WriteValue(myDR["Key2"].ToString());
								xmlWriter.WriteEndElement();//ShipmentIdentifier

							xmlWriter.WriteEndElement();//ShipControl

							xmlWriter.WriteStartElement("ShipNoticePortion");
							xmlWriter.WriteAttributeString("id", "DATA");
							//OrderNum or PONum
								xmlWriter.WriteStartElement("OrderReference");
								xmlWriter.WriteAttributeString("orderID", myDR["Key4"].ToString());

									xmlWriter.WriteStartElement("DocumentReference");
									xmlWriter.WriteAttributeString("payloadID", sDateTimeString + "PO." + myDR["Key4"].ToString() );
									xmlWriter.WriteEndElement();//DocumentReference

								xmlWriter.WriteEndElement();//OrderReference

								xmlWriter.WriteStartElement("ShipNoticeItems");
								//OrderLine or POLine
									xmlWriter.WriteAttributeString("quantity", myDR["Number01"].ToString() );
									xmlWriter.WriteAttributeString("lineNumber", myDR["Key5"].ToString() );

									xmlWriter.WriteStartElement("ItemID");
										xmlWriter.WriteStartElement("SupplierPartID");
										xmlWriter.WriteValue(myDR["ShortChar01"].ToString());
										xmlWriter.WriteEndElement();//SupplierPartID
									xmlWriter.WriteEndElement();//ItemID

									xmlWriter.WriteStartElement("UnitOfMeasure");
									xmlWriter.WriteValue("EA");
									xmlWriter.WriteEndElement();//UnitOfMeasure

								xmlWriter.WriteEndElement();//ShipNoticeItems

							xmlWriter.WriteEndElement();//ShipNoticePortion
						xmlWriter.WriteEndElement();//ShipNoticeRequest
					xmlWriter.WriteEndElement();//Request


				xmlWriter.WriteEndElement();//cXML
		
				xmlWriter.WriteEndDocument();
				xmlWriter.Flush();
				xmlWriter.Close();
				xmlWriter.Dispose();

                bResults = true;
            }
			else
			{
				throw new Exception("The ASN File Name <" + sFileName + "> must be unique." );
			} 
        }
		else
		{
			throw new Exception("Write permission for the ASN folder <" + sASNFolder + "> is denied.");
		}
    } 
    catch (Exception e) 
    {
        throw;
    } 
	finally
	{
    	if (xmlWriter != null)
		{
			xmlWriter.Flush();
			xmlWriter.Close();
			xmlWriter.Dispose();
		}
	}
    return bResults;
}
private bool UpdateASNFile(DataRowView myDR)
{
	bool bRet = false;
	XmlReader reader = null;
	XmlDocument doc = null;
	try
	{
           // Create the validating reader and specify DTD validation.
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.DtdProcessing = DtdProcessing.Parse;
            settings.ValidationType = ValidationType.DTD;
			DateTime dtNow = DateTime.Now;
			string filename = "\\EMF_" + dtNow.Year + dtNow.Month + dtNow.Day + "_PO" + myDR["Key4"].ToString() + ".xml";
            string sPath = sASNFolder; 
            sPath += filename;

            reader = XmlReader.Create(sPath);//, settings);
			//reader.Namespaces = false;
            // Pass the validating reader to the XML document.
            // Validation fails due to an undefined attribute, but the 
            // data is still loaded into the document.
            doc = new XmlDocument();
			try
			{
            	doc.Load(sPath);//ShipNoticeItem node
            	//doc.Load(reader);//ShipNoticeItem node
			}
			catch
			{
			}
			//select your specific node ..
			XmlElement el = (XmlElement)doc.SelectSingleNode("/cXML/Request/ShipNoticeRequest/ShipNoticePortion"); 
			//XmlElement el = doc.GetElementById("DATA"); 
			
			if (el != null)
			{
				XmlElement eShipNoticeItem = doc.CreateElement("ShipNoticeItem"); //item1 ,item2..
				// Create attributes for book and append them to the book element.
				XmlAttribute attribute = doc.CreateAttribute("quantity");
				attribute.Value = myDR["Number01"].ToString();
				eShipNoticeItem.Attributes.Append(attribute);
				
				attribute = doc.CreateAttribute("lineNumber");
				attribute.Value = myDR["Key5"].ToString();
				eShipNoticeItem.Attributes.Append(attribute);
				
				XmlElement eSupplierPartID = doc.CreateElement("SupplierPartID"); //item1 ,item2..
				eSupplierPartID.InnerText = myDR["ShortChar01"].ToString();
				eShipNoticeItem.AppendChild(eSupplierPartID);
				
				XmlElement eUnitOfMeasure = doc.CreateElement("UnitOfMeasure"); //item1 ,item2..
				eUnitOfMeasure.InnerText = "EA";
				eShipNoticeItem.AppendChild(eUnitOfMeasure);
				
				//el.AppendChild(eShipNoticeItem);
				el.InsertAfter(eShipNoticeItem, el.LastChild);
				doc.Save(sPath);
				bRet = true;
			}
			else
			{
				MyMessageBox("UpdateASNFile: No, the XmlElement is null. ", true, "FAILED!!");
			}
	}
    catch (Exception e) 
    {
        throw;
    } 
	finally
	{
    	if (reader != null)
			reader.Close();
    	//if (doc != null)
		//	doc.Dispose();
	}
    return bRet;
}

XML code.txt (10.7 KB)

So for more information on this. When I use th XMLReader in the UpdateASNFile method, my el (element) is not null. I am able to get all the way to the save and then I error out. It says that the file is in use. If I use the string path to open the file then the el variable is null.

So to get the project moving I decided to make the XmlWriter variable global. Since the records are created in the Customer Shipment screen, all PackIDs and lines are sequential. So I changed the code a bit.

I am still curious how to update a file and I just can’t seem to find quality examples. All of the samples that I see create very basic files. My node that I want to append to is 4 levels deep. The function to select a single node didn’t seem to work. Anyway here is my hack.

This is the ProcessSubmissions method

private bool ProcessSubmissions(ref string sErrorMessage)
{
	bool bRet = true;
	bool bSubmitCheck = false;
	bool bAllGood = false;
	sErrorMessage = string.Empty;
	string sCurrentPO = string.Empty;
	string sLastPO = string.Empty;

	
	try
	{//sASNFileText is the string to create the xml nodes
		foreach(DataRowView dr in this.edvUD01.dataView)
		{
			sCurrentPO = dr["Key4"].ToString();
			bSubmitCheck = Convert.ToBoolean(dr["CheckBox01"]);
			
			if(bSubmitCheck == true)
			{
				if(sCurrentPO != sLastPO)
				{
					if(string.IsNullOrEmpty(sLastPO) == false)
					{
						CloseXMLFile();
					}
					bAllGood = CreateASNFile(dr);
					sLastPO = sCurrentPO;
				}
				else
				{//Update xml file with POLine data
					bAllGood = UpdateASNFile(dr);
				}
				if(bAllGood == true)
				{
					
					dr.BeginEdit();
					dr["CheckBox02"] = true;
					dr.EndEdit();
					oTrans.Update();
					dr.BeginEdit();
					dr["RowMod"] = "D";
					dr.EndEdit();
					
					dr.Delete();
					oTrans.NotifyAll();
				}
			
			}
		}
	}
	catch(Exception ex)
	{
		sErrorMessage = ex.Message;
		bRet = false;
	}
	finally
	{
		CloseXMLFile();
	}

	return bRet;
}

This is the UpdateASNFile method

private bool UpdateASNFile(DataRowView myDR)
{
	bool bRet = false;

	try
	{
		xmlWriter.WriteStartElement("ShipNoticeItems");
		//OrderLine or POLine
			xmlWriter.WriteAttributeString("quantity", myDR["Number01"].ToString() );
			xmlWriter.WriteAttributeString("lineNumber", myDR["Key5"].ToString() );

			xmlWriter.WriteStartElement("ItemID");
				xmlWriter.WriteStartElement("SupplierPartID");
				xmlWriter.WriteValue(myDR["ShortChar01"].ToString());
				xmlWriter.WriteEndElement();//SupplierPartID
			xmlWriter.WriteEndElement();//ItemID

			xmlWriter.WriteStartElement("UnitOfMeasure");
			xmlWriter.WriteValue("EA");
			xmlWriter.WriteEndElement();//UnitOfMeasure

		xmlWriter.WriteEndElement();//ShipNoticeItems
		bRet = true;
	}
	catch(Exception x)
	{
		throw;
	}
	return bRet;
}

Here is a new method to close the writer when all is done.

private void CloseXMLFile()
{
	if(xmlWriter != null)
	{
					xmlWriter.WriteEndElement();//ShipNoticePortion
				xmlWriter.WriteEndElement();//ShipNoticeRequest
			xmlWriter.WriteEndElement();//Request


		xmlWriter.WriteEndElement();//cXML

		xmlWriter.WriteEndDocument();
		xmlWriter.Flush();
		xmlWriter.Close();
		xmlWriter.Dispose();
		xmlWriter = null;
	}

}