Search code examples
c#xmlxmlwriter

XMLWriter Trying to use duplicate attribute


Update: updated question to address the problem is elements and not atrributes and added my XML output

I have to feed an application some XML encoded strings (I don't use markup languages often and don't have a lot of experience with their nuances).

The format I need to send it is below(out of my control):

<ROOT>
<Unit UnitName="Unit XYZ">
<Scheds Qty="5" ProdId="214" Comments="" />
<Scheds Qty="200" ProdId="125" Comments="Need by 1/23" />
<Scheds Qty="5000" ProdId="3100" Comments="" />
</Unit>
<Unit UnitName="Unit ABC">
<Scheds Qty="5" ProdId="214" Comments="" />
<Scheds Qty="200" ProdId="125" Comments="Need by 1/25" />
<Scheds Qty="5000" ProdId="3100" Comments="" />
</Unit>
</ROOT>

I've tried to write this using XML Writer but am having issues with the Attribute Scheds being duplicate.

You can see below I was fiddling with the WriteString method but I believe I need it to be an attribute. My code below:

 //Top level root element
                writer.WriteStartElement("ROOT");

                //loop through list and determine the pu desc to create the xml element
                foreach (Tuple<int, List<PLYOrder>> t in allOrders)
                {
                    var unit = PUList.Where(x => x.PUId == t.Item1).First().PUDesc.ToString();

                    //Start each Unit as a new element
                    writer.WriteStartElement("Unit");
                    writer.WriteAttributeString("UnitName", unit);

                    foreach(PLYOrder p in t.Item2)
                    {                      
                        var qty = $"Qty=\"{p.Qty.ToString()}\"";
                        var prodId = $"ProdId=\"{p.Product.Id.ToString()}\"";
                        var Comments = $"Comments=\"{p.Comments}\"";

                    writer.WriteStartElement("Scheds", qty);
                    writer.WriteEndElement();

                    writer.WriteStartElement("Scheds", prodId);
                    writer.WriteEndElement();

                    writer.WriteStartElement("Scheds", comments);
                    writer.WriteEndElement();

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

Produces the below output in Visual Studio debugger XML view of variable:

-<ROOT>       
-<Unit UnitName="XYZ">    
<Scheds xmlns="Qty="5""/>    
<Scheds xmlns="ProdId="360""/>    
<Scheds xmlns="Comments="hhh""/>   
<Scheds xmlns="Qty="66""/>    
<Scheds xmlns="ProdId="356""/>  
<Scheds xmlns="Comments="""/>    
</Unit>       
-<Unit UnitName="ABC">    
<Scheds xmlns="Qty="44""/>    
<Scheds xmlns="ProdId="356""/>    
<Scheds xmlns="Comments="gg""/>    
</Unit>      
</ROOT>

Solution

  • It looks like you're using WriteStartElement incorrectly. The second parameter is not an attribute, but a namespace URI. Here's a simple example

    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.OmitXmlDeclaration = true;
    XmlWriter writer = XmlWriter.Create(Console.Out, settings);
    
    writer.WriteStartElement("ROOT");
    
    writer.WriteStartElement("Unit");
    writer.WriteAttributeString("UnitName", "Unit XYZ");
    writer.WriteEndElement();
    
    writer.WriteStartElement("Scheds");
    writer.WriteAttributeString("Qty", "5");
    writer.WriteAttributeString("ProdId", "214");
    writer.WriteAttributeString("Comments", "Need by 1/25");
    writer.WriteEndElement();
    
    // Write the close tag for the root element.
    writer.WriteEndElement();
    writer.Close(); 
    

    This produces the following output:

    <ROOT>
      <Unit UnitName="Unit XYZ" />
      <Scheds Qty="5" ProdId="214" Comments="Need by 1/25" />
    </ROOT>
    

    So from your example it would be:

    foreach(PLYOrder p in t.Item2)
    { 
        writer.WriteStartElement("Scheds");
        writer.WriteAttributeString("Qty", p.Qty.ToString());
        writer.WriteAttributeString("ProdId", p.Product.Id.ToString());
        writer.WriteAttributeString("Comments", p.Comments);
        writer.WriteEndElement();
    }