You have an XML document that needs to be broken apart into its constituent parts. Each part can then be sent to a different destination (possibly a web service) to be processed individually. This solution is useful when you have a large document, such as an invoice, in XML form. For example, with an invoice, you would want to tear off the billing information and send this to accounting while sending the shipping information to shipping, and then send the invoice items to fulfillment to be processed.
In order to
separate the invoice items, we will load an
XmlDocument
with the invoice XML from the
Invoice.xml
file:
<?xml version="1.0" encoding="UTF-8"?> <Invoice invoiceDate='2003-10-05' invoiceNumber='INV-01'> <shipInfo> <name>Beerly Standing</name> <attn>Receiving</attn> <street>47 South Street</street> <city>Intox</city> <state>NH</state> </shipInfo> <billInfo> <name>Beerly Standing</name> <attn>Accounting</attn> <street>98 North Street</street> <city>Intox</city> <state>NH</state> </billInfo> <Items> <item partNum="98745"> <productName>Brown Eyed Stout</productName> <quantity>12</quantity> <price>23.99</price> <shipDate>2003-12-20</shipDate> </item> <item partNum="34987"> <productName>Diamond Pearl Lager</productName> <quantity>22</quantity> <price>35.98</price> <shipDate>2003-12-20</shipDate> </item> <item partNum="AK254"> <productName>Job Site Ale</productName> <quantity>50</quantity> <price>12.56</price> <shipDate>2003-11-12</shipDate> </item> </Items> </Invoice>
The code to tear this invoice apart, and send the various information pieces to their respective departments, is shown here:
public static void ProcessInvoice( ) { XmlDocument xmlDoc = new XmlDocument( ); // pick up invoice from deposited directory xmlDoc.Load(@"....Invoice.xml"); // get the Invoice element node XmlNode Invoice = xmlDoc.SelectSingleNode("/Invoice"); // get the invoice date attribute XmlAttribute invDate = (XmlAttribute)Invoice.Attributes.GetNamedItem("invoiceDate"); // get the invoice number attribute XmlAttribute invNum = (XmlAttribute)Invoice.Attributes.GetNamedItem("invoiceNumber"); // Process the billing information to Accounting XmlElement billingEnvelope = xmlDoc.CreateElement("BillingEnvelope"); // correlate this information back to the original invoice number and date billingEnvelope.Attributes.Append((XmlAttribute)invDate.Clone( )); billingEnvelope.Attributes.Append((XmlAttribute)invNum.Clone( )); XmlNodeList billList = xmlDoc.SelectNodes("/Invoice/billInfo"); // add the billing information to the envelope foreach(XmlNode billInfo in billList) { billingEnvelope.AppendChild(billInfo.Clone( )); } Console.WriteLine("BillingEnvelope: {0}",billingEnvelope.OuterXml); // Save a copy of the envelope FileStream fileStream = File.Create(@"....BillingEnvelope.xml"); byte [] bytes = Encoding.ASCII.GetBytes(billingEnvelope.OuterXml); fileStream.Write(bytes,0,bytes.Length); fileStream.Close( ); // Process the shipping information to Shipping XmlElement shippingEnvelope = xmlDoc.CreateElement("ShippingEnvelope"); // correlate this information back to the original invoice number and date shippingEnvelope.Attributes.Append((XmlAttribute)invDate.Clone( )); shippingEnvelope.Attributes.Append((XmlAttribute)invNum.Clone( )); XmlNodeList shipList = xmlDoc.SelectNodes("/Invoice/shipInfo"); // add the shipping information to the envelope foreach(XmlNode shipInfo in shipList) { shippingEnvelope.AppendChild(shipInfo.Clone( )); } Console.WriteLine("ShippingEnvelope: {0}",shippingEnvelope.OuterXml); // Save a copy of the envelope fileStream = File.Create(@"....ShippingEnvelope.xml"); bytes = Encoding.ASCII.GetBytes(shippingEnvelope.OuterXml); fileStream.Write(bytes,0,bytes.Length); fileStream.Close( ); // Process the item information to Fulfillment XmlElement fulfillmentEnvelope = xmlDoc.CreateElement("FulfillmentEnvelope"); // correlate this information back to the original invoice number and date fulfillmentEnvelope.Attributes.Append((XmlAttribute)invDate.Clone( )); fulfillmentEnvelope.Attributes.Append((XmlAttribute)invNum.Clone( )); XmlNodeList itemList = xmlDoc.SelectNodes("/Invoice/Items/item"); // add the item information to the envelope foreach(XmlNode item in itemList) { fulfillmentEnvelope.AppendChild(item.Clone( )); } Console.WriteLine("FulfillmentEnvelope: {0}",fulfillmentEnvelope.OuterXml); // Save a copy of the envelope fileStream = File.Create(@"....FulfillmentEnvelope.xml"); bytes = Encoding.ASCII.GetBytes(fulfillmentEnvelope.OuterXml); fileStream.Write(bytes,0,bytes.Length); fileStream.Close( ); // Now send the data to the web services ... }
The “envelopes” containing the various pieces of XML data for the web services are listed in the following sections:
<BillingEnvelope invoiceDate="2003-10-05" invoiceNumber="INV-01"> <billInfo> <name>Beerly Standing</name> <attn>Accounting</attn> <street>98 North Street</street> <city>Intox</city> <state>NH</state> </billInfo> </BillingEnvelope>
<ShippingEnvelope invoiceDate="2003-10-05" invoiceNumber="INV-01"> <shipInfo> <name>Beerly Standing</name> <attn>Receiving</attn> <street>47 South Street</street> <city>Intox</city> <state>NH</state> </shipInfo> </ShippingEnvelope>
<FulfillmentEnvelope invoiceDate="2003-10-05" invoiceNumber="INV-01"> <item partNum="98745"> <productName>Brown Eyed Stout</productName> <quantity>12</quantity> <price>23.99</price> <shipDate>2003-12-20</shipDate> </item> <item partNum="34987"> <productName>Diamond Pearl Lager</productName> <quantity>22</quantity> <price>35.98</price> <shipDate>2003-12-20</shipDate> </item> <item partNum="AK254"> <productName>Job Site Ale</productName> <quantity>50</quantity> <price>12.56</price> <shipDate>2003-11-12</shipDate> </item> </FulfillmentEnvelope>
In order to tear apart the invoice, we needed to establish what
pieces would go to which departments. The breakdown of this is that
each of the envelopes would get the invoice date and invoice number
from the main invoice to give context to the information in the
envelope. The billInfo
element and children would
go to the BillingEnvelope
, the
shipInfo
element and children would go to the
ShippingEnvelope
, and the item
elements would go to the FulfillmentEnvelope
. Once
these envelopes were constructed, they would be sent to the web
services for each department that accepts the data to perform their
function for this invoice.
In the example program from the solution, we first loaded the
Invoice.xml
file and got the attributes we were
going to give to each of the envelopes:
XmlDocument xmlDoc = new XmlDocument( ); // pick up invoice from deposited directory xmlDoc.Load(@"....Invoice.xml"); // get the Invoice element node XmlNode Invoice = xmlDoc.SelectSingleNode("/Invoice"); // get the invoice date attribute XmlAttribute invDate = (XmlAttribute)Invoice.Attributes.GetNamedItem("invoiceDate"); // get the invoice number attribute XmlAttribute invNum = (XmlAttribute)Invoice.Attributes.GetNamedItem("invoiceNumber");
Then we established each envelope with the sections of the invoice
that matter to the respective functions (the
BillingEnvelope
is handled by Accounting, the
ShippingEnveloper
is handled by Shipping, and the
FulfillmentEnvelope
is handled by
Fulfillment
, starting with the
BillingEnvelope
:
// Process the billing information to Accounting XmlElement billingEnvelope = xmlDoc.CreateElement("BillingEnvelope"); // correlate this information back to the original invoice number and date billingEnvelope.Attributes.Append((XmlAttribute)invDate.Clone( )); billingEnvelope.Attributes.Append((XmlAttribute)invNum.Clone( )); XmlNodeList billList = xmlDoc.SelectNodes("/Invoice/billInfo"); // add the billing information to the envelope foreach(XmlNode billInfo in billList) { billingEnvelope.AppendChild(billInfo.Clone( )); } Console.WriteLine("BillingEnvelope: {0}",billingEnvelope.OuterXml); // Save a copy of the envelope FileStream fileStream = File.Create(@"....BillingEnvelope.xml"); byte [] bytes = Encoding.ASCII.GetBytes(billingEnvelope.OuterXml); fileStream.Write(bytes,0,bytes.Length); fileStream.Close( );
Then the ShippingEnvelope
was created:
// Process the shipping information to Shipping XmlElement shippingEnvelope = xmlDoc.CreateElement("ShippingEnvelope"); // correlate this information back to the original invoice number and date shippingEnvelope.Attributes.Append((XmlAttribute)invDate.Clone( )); shippingEnvelope.Attributes.Append((XmlAttribute)invNum.Clone( )); XmlNodeList shipList = xmlDoc.SelectNodes("/Invoice/shipInfo"); // add the shipping information to the envelope foreach(XmlNode shipInfo in shipList) { shippingEnvelope.AppendChild(shipInfo.Clone( )); } Console.WriteLine("ShippingEnvelope: {0}",shippingEnvelope.OuterXml); // Save a copy of the envelope fileStream = File.Create(@"....ShippingEnvelope.xml"); bytes = Encoding.ASCII.GetBytes(shippingEnvelope.OuterXml); fileStream.Write(bytes,0,bytes.Length); fileStream.Close( );
Finally, the FulfillmentEnvelope
was created:
// Process the item information to Fulfillment XmlElement fulfillmentEnvelope = xmlDoc.CreateElement("FulfillmentEnvelope"); // correlate this information back to the original invoice number and date fulfillmentEnvelope.Attributes.Append((XmlAttribute)invDate.Clone( )); fulfillmentEnvelope.Attributes.Append((XmlAttribute)invNum.Clone( )); XmlNodeList itemList = xmlDoc.SelectNodes("/Invoice/Items/item"); // add the item information to the envelope foreach(XmlNode item in itemList) { fulfillmentEnvelope.AppendChild(item.Clone( )); } Console.WriteLine("FulfillmentEnvelope: {0}",fulfillmentEnvelope.OuterXml); // Save a copy of the envelope fileStream = File.Create(@"....FulfillmentEnvelope.xml"); bytes = Encoding.ASCII.GetBytes(fulfillmentEnvelope.OuterXml); fileStream.Write(bytes,0,bytes.Length); fileStream.Close( );
At this point, each of the envelopes could be posted to the respective web service interfaces.
Note that when we appended the attributes from the
Invoice
to the envelopes, we called the
XmlNode.Clone
method on the XmlAttributes
. This is done so that
each of the elements had their own separate copy. If you do not do
this, then the attribute will appear only on the last element it was
assigned to.