John Fischer John Fischer - 3 months ago 11
C# Question

How to write the Child Elements using XDocument

I have revised the question and included the code I have write so far for this question. Below is an example of what the output must look like to be compatible with the VeriFone MX915 Payment terminal. In this specific part, I am trying to send the POS register items to the display.

<TRANSACTION>
<FUNCTION_TYPE>LINE_ITEM</FUNCTION_TYPE>
<COMMAND>ADD</COMMAND>
<COUNTER>1</COUNTER>
<MAC> … </MAC>
<MAC_LABEL>REG2</MAC_LABEL>
<RUNNING_SUB_TOTAL>7.00</RUNNING_SUB_TOTAL>
<RUNNING_TRANS_AMOUNT>7.42</RUNNING_TRANS_AMOUNT>
<RUNNING_TAX_AMOUNT>0.42</RUNNING_TAX_AMOUNT>
<LINE_ITEMS>
<MERCHANDISE>
<UNIT_PRICE>5.00</UNIT_PRICE>
<DESCRIPTION>#1 Combo Meal</DESCRIPTION>
<LINE_ITEM_ID>1695155651</LINE_ITEM_ID>
<EXTENDED_PRICE>5.00</EXTENDED_PRICE>
<QUANTITY>1</QUANTITY>
</MERCHANDISE>
</LINE_ITEMS>
</TRANSACTION>


The SDK supplied by VeriFone has made some of the methods needed to communicate with the device. So the following code has method calls and class level variables that are written but not included in the following example:

/// <summary>
/// Send 1 or more items to the Verifone display. Include subtotal, tax and total
/// </summary>
/// <param name="nSubTotal">Subtotal of transaction</param>
/// <param name="nTax">Current Tax of transaction</param>
/// <param name="nTotal">Total of transaction</param>
/// <param name="UPC">Item Code</param>
/// <param name="ShortDescription">Small description</param>
/// <param name="nItemAmount">Item Amt</param>
/// <param name="nQty">Quantity</param>
/// <param name="nExtendedAmount">Quantity X Item Amt</param>
/// <returns></returns>
public bool AddLineItem(double nSubTotal, double nTax, double nTotal, Int32 nItemID, string UPC, string ShortDescription, double nItemAmount, Int32 nQty, double nExtendedAmount)
{

// get counter and calculate Mac
var nextCounter = (++counter).ToString();
var mac = PrintMacAsBase64(macKey, nextCounter);

// build request
var request = new XDocument();
using (var writer = request.CreateWriter())
{
//populate the elements
writer.WriteStartDocument();
writer.WriteStartElement("TRANSACTION");
writer.WriteElementString("FUNCTION_TYPE", "LINE_ITEM");
writer.WriteElementString("COMMAND", "ADD");
writer.WriteElementString("MAC_LABEL", macLabel);
writer.WriteElementString("COUNTER", nextCounter);
writer.WriteElementString("MAC", mac);
writer.WriteElementString("RUNNING_SUB_TOTAL",nSubTotal.ToString("c"));
writer.WriteElementString("RUNNING_TAX_AMOUNT",nTax.ToString("c"));
writer.WriteElementString("RUNNING_TRANS_AMOUNT",nTotal.ToString("c"));

//HERE IS WHERE I NEED TO WRITE THE CHILD ELEMENT(s):

//example below of what they or it would look like
//(collection of merchandise elements under Line_items)
//I know this example will have only one item because of parameters

/*
<LINE_ITEMS>
<MERCHANDISE>
<LINE_ITEM_ID>10</LINE_ITEM_ID>
<DESCRIPTION>This is a dummy</DESCRIPTION>
<UNIT_PRICE>1.00</UNIT_PRICE>
<QUANTITY>1</QUANTITY>
<EXTENDED_PRICE>1.00</EXTENDED_PRICE>
</MERCHANDISE>
</LINE_ITEMS>
*/

writer.WriteEndElement();
writer.WriteEndDocument();
}

// transmit to Point Solution and interrogate the response
var responseXml = Send(address, port, request);


//DO SOMETHING HERE WITH THE RESPONSE
// validate that the RESULT_CODE came back a SUCCESS
if ("-1" != responseXml.Element("RESPONSE").Element("RESULT_CODE").Value)
{
throw new Exception(responseXml.Element("RESPONSE").Element("RESULT_TEXT").Value ?? "unknown error");
}
return true;


}


If any one can help me understand how to populate the child elements as indicated where I put comments in the code I will be very thankful.

Thanks to the moderators for requesting more information on this.

Answer

I think using XmlSerializer is a good idea, maybe codes below could help you. XmlSerializer is more intuitive than XmlWriter to generate Xml. : )

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

class Program
{
    static void Main(string[] args)
    {
        Transaction transaction = new Transaction();
        transaction.Function_Type = "LINE_ITEM";
        transaction.LineItems = new List<Merchandise>();
        transaction.LineItems.Add(new Merchandise() { UnitPrice = "5.00" });

        //Create our own namespaces for the output
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

        //Add an empty namespace and empty value
        ns.Add("", "");

        using (XmlWriter writer = XmlWriter.Create(Console.Out, new XmlWriterSettings { OmitXmlDeclaration = true }))
        {
            new XmlSerializer(typeof(Transaction)).Serialize(writer, transaction, ns);
        }

        Console.Read();
    }
}

[XmlRoot("TRANSACTION")]
public class Transaction
{
    [XmlElement("FUNCTION_TYPE")]
    public string Function_Type { get; set; }

    [XmlArray("LINE_ITEMS")]
    [XmlArrayItem("MERCHANDISE")]
    public List<Merchandise> LineItems { get; set; }
}

[XmlRoot("MERCHANDISE")]
public class Merchandise
{
    [XmlElement("UNIT_PRICE")]
    public string UnitPrice { get; set; }
}

Results:
enter image description here