0

I'm totally new to C#. I have to write a xml file which similarly looks like.

<DATA_SET SampleSize="5"> 
<DATA SampleID="1" IW="0.889" SL="24.24" PO="117" /> 
<DATA SampleID="2" IW="0.896" SL="24.41" PO="119" /> 
<DATA SampleID="3" IW="0.922" SL="24.3" PO="125" /> 
<DATA SampleID="4" IW="0.94" SL="24.24" PO="129" /> 
<DATA SampleID="5" IW="0.987" SL="24.32" PO="127" /> 
</DATA_SET>

What I have to tried is,

if (oneSet.Length == 5)
{
    qtm.SampleID = oneSet[0];//ROD
    qtm.SL = oneSet[1];//SIZEmmL
    qtm.SY = oneSet[2];//OVALmm
    qtm.RP = oneSet[3];//ROUND%
    qtm.VN = oneSet[4];//VENT%
    lstQTM.Add(qtm);
    isSet = true;
}

Here QTM is a class, through this class I have made list. SampleID,SL,SY,RP,VN are the methods of QTM class file. By using above code I added those into a list.

using (FileStream fs = new FileStream("D:\\B.xml", FileMode.Create))
{
 new XmlSerializer(typeof(List<QTM>)).Serialize(fs, lstQTM);
}

My out put is

  <QTM>
    <SampleID>ROD</SampleID>
    <SL>WTg</SL>
    <SY>SIZEmmL</SY>
    <RP>OVALmm</RP>
    <VN>PDmm</VN>
  </QTM>
  <QTM>
    <SampleID>1</SampleID>
    <SL>0.740</SL>
    <SY>23.94</SY>
    <RP>0.28</RP>
    <VN>357</VN>
  </QTM>
  <QTM>
    <SampleID>2</SampleID>
    <SL>0.751</SL>
    <SY>23.98</SY>
    <RP>0.29</RP>
    <VN>368</VN>
  </QTM>
  <QTM>
    <SampleID>3</SampleID>
    <SL>0.733</SL>
    <SY>23.95</SY>
    <RP>0.39</RP>
    <VN>351</VN>
  </QTM>
  <QTM>
    <SampleID>4</SampleID>
    <SL>0.747</SL>
    <SY>23.99</SY>
    <RP>0.32</RP>
    <VN>363</VN>
  </QTM>
  <QTM>
    <SampleID>5</SampleID>
    <SL>0.734</SL>
    <SY>23.96</SY>
    <RP>0.23</RP>
    <VN>356</VN>
  </QTM>
  <QTM>
    <SampleID>6</SampleID>
    <SL>0.742</SL>
    <SY>23.89</SY>
    <RP>0.64</RP>
    <VN>365</VN>
  </QTM>
</ArrayOfQTM>

How can I do this. could you please give me any idea.

Arebhy Sridaran
  • 586
  • 12
  • 28
  • 1
    Take the result Xml copy it. Past special in visual studio "xml as class". use the class serialise them. – xdtTransform May 10 '19 at 11:25
  • 2
    Possible duplicate of [How can I build XML in C#?](https://stackoverflow.com/questions/284324/how-can-i-build-xml-in-c) – xdtTransform May 10 '19 at 11:26
  • `[XmlRoot(ElementName="DATA")] public class DATA { [XmlAttribute(AttributeName="SampleID")] public string SampleID { get; set; } [XmlAttribute(AttributeName="IW")] public string IW { get; set; } [XmlAttribute(AttributeName="SL")] public string SL { get; set; } [XmlAttribute(AttributeName="PO")] public string PO { get; set; } }` class will look like – xdtTransform May 10 '19 at 11:27
  • To have value in attribute use the Xml Atrribute : `[XmlAttribute(AttributeName="SampleID")]` – xdtTransform May 10 '19 at 11:28

3 Answers3

1

In your C# classes you can add attributes to your member variables that will change how XmlSerializer will behave. For example, the following will make the SampleID be serialised as an attribute rather than an element:

public class QTM {
    [XmlAttribute("SampleID")]
    public int SampleID;
}

See the documentation for more information here

kevernicus
  • 344
  • 1
  • 5
1

Update

As noted by Rand Random, I misread the original question. Therefore, be awate of it. I quote the comment for future reference.

As note by the comment, the OP is indeed aware of the mechanism, but didn't know that he needs a root object and that he can change a XmlElement to XmlAttribute by declaring it with attributes

If you want to read an XML document without dirtying your hands, you can use XmlSerializer.

It is super easy. First you create POCO (classes with only properties) that mimick the XML file you want to read. Start from the root:

[XmlRoot("DATA_SET ")]
public sealed class MyRoot
{
    [XmlElement("sampleSize")]
    public int SampleSize { get; set; }

    [XmlArrayItem("data")]
    public List<MyData> Data { get; set; }

}

The above code models the root. It is as verbose as possible, in order to understand what you are effectively doing.

Then, you model the inner node:

[Serializable]
public sealed class MyData
{
    [XmlAttribute("SampleID")]
    public int SampleId { get; set; }

    [XmlAttribute("IW")]
    public double WhateverThisIs1 { get; set; }

    [XmlAttribute("SL")]
    public double WhateverThisIs2 { get; set; }

    [XmlAttribute("PO")]
    public int WhateverThisIs3 { get; set; }
}

The above code declares the properties with the names you want in C#, mapped to the names you expect in your xml file. As you can see they differ.

Finally, you can read your file in this way:

var serializer = new XmlSerializer(typeof(MyRoot));

using (var reader = new StreamReader(fileName))
{
    var root = (MyRoot)serializer.Deserialize(reader);
    // do something with root.
}

Note: You might have to adjust the root node to properly handle its children node, in case the hierarchy is more complex.

You can read more at MSDN

Community
  • 1
  • 1
Yennefer
  • 5,704
  • 7
  • 31
  • 44
  • 1
    Your answer seems like you didn't realise that OP is already serializing an object to XML, it's that the output he is getting isn't what he desires. – Rand Random May 10 '19 at 11:34
  • Doh!! In effect... it seems that I read what I wanted to read:) You are right. – Yennefer May 10 '19 at 11:35
  • Unless there is a need for this answer (although I spent effort on that), I am gonna delete it. – Yennefer May 10 '19 at 11:36
  • 1
    I would suggest keeping the answer, since it is correct and complete - just reword it so that you aknowledge that OP is already aware of `XMLSerializer` but didn't know that he needs a `root` object and that he can change a `XmlElement` to `XmlAttribute` by declaring it with attributes. – Rand Random May 10 '19 at 11:39
  • Thank you, I added a disclaimer. Hope it is sufficient. In any cases, thank you for your support. – Yennefer May 10 '19 at 14:11
1

Here's an example class structure which preserves the structure of the QTM class you already have, but still gives the XML that you want to get.

[XmlRoot("DATA_SET")]
public class QTMCollection
{
    [XmlElement("DATA")]
    public List<QTM> QTMs { get; set; }

    [XmlAttribute("SampleSize")]
    public int SampleSize { get { return QTMs.Count; } set { return; } }        
}

public class QTM
{
    [XmlAttribute]
    public int SampleId { get; set; }
    [XmlAttribute]
    public decimal IW { get; set; }
    [XmlAttribute]
    public decimal SL { get; set; }
    [XmlAttribute]
    public int PO { get; set; }        
}

We need an outer class structure here - mainly driven by the SampleSize attribute on the outer DATA_SET element, otherwise we wouldn't have to have it.

There are some quirks here - XmlSerializer will only serialize properties that have a getter and setter, which is why I have the otherwise unnecessary setter on SampleSize. The XmlRoot, XmlAttribute and XmlElement serve to tell the serializer what to call your classes and properties in the XML.

Here is an example of how to invoke the serializer to get an xml exactly like your example:

QTMCollection collection = new ConsoleApplication135.QTMCollection()
{
    QTMs = new List<QTM>
    {
        new QTM() { SampleId = 1, IW = 0.0889M, SL = 24.24M, PO = 117 },
        new QTM() { SampleId = 2, IW = 0.896M, SL = 24.41M, PO = 119 },
        new QTM() { SampleId = 3, IW = 0.922M, SL = 24.3M, PO = 125 },
        new QTM() { SampleId = 4, IW = 0.94M, SL = 24.24M, PO = 129 },
        new QTM() { SampleId = 5, IW = 0.987M, SL = 24.32M, PO = 127 }
    }
};            

using (FileStream fileStream = new FileStream(@"c:\temp\B.xml", FileMode.Create))
{                
    using (var writer = XmlWriter.Create(fileStream, new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true }))
    {
        var serializer = new XmlSerializer(typeof(QTMCollection));
        serializer.Serialize(writer, collection, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty }));
    }
}

The reason for using XmlWriterSettings (and so the XmlWriter) here is to omit the Xml declaration at the top of the XML that would otherwise appear:

<?xml version="1.0" encoding="utf-8"?>

And the purpose of this:

new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty })

Is to avoid the default namespace declaration on the root element that would otherwise appear:

<DATA_SET xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SampleSize="5">

Whereas with both those things, the output will be an unadorned XML like this:

<DATA_SET SampleSize="5">
  <DATA SampleId="1" IW="0.0889" SL="24.24" PO="117" />
  <DATA SampleId="2" IW="0.896" SL="24.41" PO="119" />
  <DATA SampleId="3" IW="0.922" SL="24.3" PO="125" />
  <DATA SampleId="4" IW="0.94" SL="24.24" PO="129" />
  <DATA SampleId="5" IW="0.987" SL="24.32" PO="127" />
</DATA_SET>
steve16351
  • 5,372
  • 2
  • 16
  • 29