Can't read from xml into an <> using linq, get nulls - c#

I have an XML file:
<?xml version="1.0" encoding="us-ascii"?>
<TestItems xmlns="http://www.blogger.com">
<TestItem correct="0" incorrect="0">
<Question>question</Question>
<Answer>answer</Answer>
<Tags>test1;test2</Tags>
</TestItem>
<TestItem correct="0" incorrect="0">
<Question>question3</Question>
<Answer>answer3</Answer>
<Tags>tagA;tagB;tagC</Tags>
</TestItem>
</TestItems>
I also have an object:
class TestItem
{
public string Question { get; set; }
public string Answer { get; set; }
public int NumberCorrect { get; set; }
public int NumberIncorrect { get; set; }
public string Tags { get; set; }
}
And here is the code that I use to read the data into memory:
XDocument ktdb = XDocument.Load("KTdb.xml");
XNamespace ns = ktdb.Root.Name.Namespace;
var testItems = from item in ktdb.Descendants(ns + "TestItem")
select new TestItem
{
Question = item.Element(ns + "Question").Value,
Answer = (string)item.Element(ns + "Answer").Value,
Tags = item.Element(ns + "Tags").Value,
NumberCorrect = Convert.ToInt32(item.Attribute(ns + "correct").Value),
NumberIncorrect = Convert.ToInt32(item.Attribute(ns + "incorrect").Value)
};
But it would not let me do that. When the LINQ statement is executed, the default constructor is called on the TestItem object, and then I get the null exception because item.Element(ns + "Question").Value is null.
Why do I get the error? How do I fix my code?
Thanks.

Change this:
NumberCorrect = Convert.ToInt32(item.Attribute(ns + "correct").Value),
NumberIncorrect = Convert.ToInt32(item.Attribute(ns + "incorrect").Value)
To this:
NumberCorrect = Convert.ToInt32(item.Attribute("correct").Value),
NumberIncorrect = Convert.ToInt32(item.Attribute("incorrect").Value)
i.e. Remove the concatenation of ns from the attribute name.

Related

C# Searching MongoDB string that starts with "xyz"

I try to code a Storagesystem and i got one Problem and dont know how to solve it...
public static List<string> GetAllItemsFromDB(string Searchbar)
{
List<string> retList = new List<string>();
retList.Clear();
var filter = Builders<DB_Package_Item>.Filter.Eq(Item => Item.Item_Name, Searchbar);
var ItemsMatch = Item_DB.Find(filter).ToList();
foreach (var Item in ItemsMatch.ToList())
{
retList.Add(Item.Item_Name);
}
return retList;
}
This Works. But when i change the filter to:
var filter = Builders<DB_Package_Item>.Filter.ElemMatch(Item => Item.Item_Name, Searchbar);
It crasches as soon i type any char in the searchbar with Error code : "System.InvalidOperationException: "The serializer for field 'Item_Name' must implement IBsonArraySerializer and provide item serialization info."
"
I just dont get it why...
This is the Data_Package for MongoDB
public class DB_Package_Item
{
public Guid Id { get; set; }
public int Item_ID { get; set; }
public int Box_ID { get; set; }
public string Item_Name { get; set; }
public int Quantity { get; set; }
public string Partnumber { get; set; }
public string Supplier { get; set; }
}
Thx for every help!
FilterDefinitionBuilder<TDocument>.ElemMatch<TItem> or $elemMatch operator is for searching the item in the array field, which is not appropriate for your scenario to search (term) for a string field.
You need the $regex operator which is FilterDefinitionBuilder<TDocument>.Regex in C# syntax.
using System.Text.RegularExpressions;
var filter = Builders<DB_Package_Item>.Filter.Regex(Item => Item.Item_Name
, new Regex("^" + Searchbar));
For case-insensitive:
new Regex("^" + Searchbar, RegexOptions.IgnoreCase)
Or
var filter = Builders<DB_Package_Item>.Filter.Regex(Item => Item.Item_Name
, new BsonRegularExpression("^" + Searchbar));
For case-insensitive,
new BsonRegularExpression("^" + Searchbar, "i")

Read XML to linq object, then create XML

I have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<pp010 xmlns="http://www.123456768.com/technology">
<rptHdr>
<exchNam>MyXML</exchNam>
<envText>P</envText>
<rptCod>pp010</rptCod>
<rptNam>Daily Stock</rptNam>
<membLglNam>CompanyA</membLglNam>
<rptPrntEffDat>2015-04-14</rptPrntEffDat>
<rptPrntRunDat>2015-04-14</rptPrntRunDat>
</rptHdr>
<pp010Grp>
<pp010KeyGrp>
<membClgIdCod>HBGKP</membClgIdCod>
</pp010KeyGrp>
<pp010Grp1>
<pp010KeyGrp1>
<membExchIdCod>JBGJG</membExchIdCod>
</pp010KeyGrp1>
<pp010Grp2>
<pp010KeyGrp2>
<currTypCod>CHF</currTypCod>
</pp010KeyGrp2>
<pp010Grp3>
<pp010KeyGrp3>
<acctTypGrp>PP</acctTypGrp>
</pp010KeyGrp3>
<pp010Rec>
<mgnGrpCod> </mgnGrpCod>
<mgnClsCod>CSLN </mgnClsCod>
<mgnPremiumAmnt>+222926.00</mgnPremiumAmnt>
<mgnLiqDlvAmnt>+0.00</mgnLiqDlvAmnt>
<mgnSprdAmnt>+0.00</mgnSprdAmnt>
<mgnAddlAmnt>+89349.30</mgnAddlAmnt>
<unadjMgnReq>+312275.30</unadjMgnReq>
</pp010Rec>
<pp010Rec>
<mgnGrpCod> </mgnGrpCod>
<mgnClsCod>CSLM </mgnClsCod>
<mgnPremiumAmnt>+55112.00</mgnPremiumAmnt>
<mgnLiqDlvAmnt>+0.00</mgnLiqDlvAmnt>
<mgnSprdAmnt>+0.00</mgnSprdAmnt>
<mgnAddlAmnt>+30854.40</mgnAddlAmnt>
<unadjMgnReq>+85966.40</unadjMgnReq>
</pp010Rec>
I am using the following code but cannot seem to create an IEnumberable with the data from ...
public class MarginRep
{
public string mgnGrpCod {get;set;}
public string mgnClsCod {get;set;}
public string mgnPremiumAmnt {get;set;}
public string mgnLiqDlvAmnt {get;set;}
public string mgnSprdAmnt {get;set;}
public string mgnAddlAmnt {get;set;}
public string unadjMgnReq {get;set;}
}
private void button1_Click(object sender, EventArgs e)
{
string file = #"D:\WorkDesktop\VisualStudio\file.xml";
XDocument xmlDoc = XDocument.Load(file);
IEnumerable<MarginRep> myMarginRep =
from c in xmlDoc.Descendants("pp010Rec")
select new MarginRep()
{
mgnGrpCod = (string)c.Attribute("mgnGrpCod"),
mgnClsCod = (string)c.Attribute("mgnClsCod"),
mgnPremiumAmnt = (string)c.Attribute("mgnPremiumAmnt"),
mgnLiqDlvAmnt = (string)c.Attribute("mgnLiqDlvAmnt"),
mgnSprdAmnt = (string)c.Attribute("mgnSprdAmnt"),
mgnAddlAmnt = (string)c.Attribute("mgnAddlAmnt"),
unadjMgnReq = (string)c.Attribute("unadjMgnReq"),
};
}
Sorry for the large amount of the XML. I felt i needed to display it as the first couple of lines i dont need and cannot seem to navigate down the pp010Rec
IF you can offer any help I would be grateful, if you can point me into the direction literature I can spend time reading and try it alone.
Cheers,
It seems you want the values not the attributes, so change:
mgnGrpCod = (string)c.Attribute("mgnGrpCod"),
To:
mgnGrpCod = (string)c.Element("mgnGrpCod").Value,
Do the same with the other properties
I a bit changed .xml:
<?xml version="1.0" encoding="UTF-8"?>
<pp010 xmlns="http://www.123456768.com/technology">
<rptHdr>
<exchNam>MyXML</exchNam>
<envText>P</envText>
<rptCod>pp010</rptCod>
<rptNam>Daily Stock</rptNam>
<membLglNam>CompanyA</membLglNam>
<rptPrntEffDat>2015-04-14</rptPrntEffDat>
<rptPrntRunDat>2015-04-14</rptPrntRunDat>
</rptHdr>
<pp010Grp>
<pp0510KeyGrp>
<membClgIdCod>HBGKP</membClgIdCod>
</pp0510KeyGrp>
<pp010Grp1>
<pp010KeyGrp1>
<membExchIdCod>JBGJG</membExchIdCod>
</pp010KeyGrp1>
<pp010Grp2>
<pp010KeyGrp2>
<currTypCod>CHF</currTypCod>
</pp010KeyGrp2>
<pp010Grp3>
<pp010KeyGrp3>
<acctTypGrp>PP</acctTypGrp>
</pp010KeyGrp3>
<pp010Rec>
<mgnGrpCod> </mgnGrpCod>
<mgnClsCod>CSLN </mgnClsCod>
<mgnPremiumAmnt>+222926.00</mgnPremiumAmnt>
<mgnLiqDlvAmnt>+0.00</mgnLiqDlvAmnt>
<mgnSprdAmnt>+0.00</mgnSprdAmnt>
<mgnAddlAmnt>+89349.30</mgnAddlAmnt>
<unadjMgnReq>+312275.30</unadjMgnReq>
</pp010Rec>
<pp010Rec>
<mgnGrpCod> </mgnGrpCod>
<mgnClsCod>CSLM </mgnClsCod>
<mgnPremiumAmnt>+55112.00</mgnPremiumAmnt>
<mgnLiqDlvAmnt>+0.00</mgnLiqDlvAmnt>
<mgnSprdAmnt>+0.00</mgnSprdAmnt>
<mgnAddlAmnt>+30854.40</mgnAddlAmnt>
<unadjMgnReq>+85966.40</unadjMgnReq>
</pp010Rec>
</pp010Grp3>
</pp010Grp2>
</pp010Grp1>
</pp010Grp>
</pp010>
So you can run
public class MarginRep
{
public string mgnGrpCod { get; set; }
public string mgnClsCod { get; set; }
public string mgnPremiumAmnt { get; set; }
public string mgnLiqDlvAmnt { get; set; }
public string mgnSprdAmnt { get; set; }
public string mgnAddlAmnt { get; set; }
public string unadjMgnReq { get; set; }
public override string ToString()
{
return string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}",
mgnGrpCod, mgnClsCod, mgnPremiumAmnt, mgnLiqDlvAmnt, mgnSprdAmnt,
mgnAddlAmnt, unadjMgnReq);
}
}
var xmlDoc = XDocument.Load("1.xml");
XNamespace xn = xmlDoc.Root.Name.Namespace;
IEnumerable<MarginRep> myMarginRep = xmlDoc.Root.Descendants(xn + "pp010Rec")
.Select(c => new MarginRep()
{
mgnGrpCod = c.Element(xn + "mgnGrpCod").Value,
mgnClsCod = c.Element(xn + "mgnClsCod").Value,
mgnPremiumAmnt = c.Element(xn + "mgnPremiumAmnt").Value,
mgnLiqDlvAmnt = c.Element(xn + "mgnLiqDlvAmnt").Value,
mgnSprdAmnt = c.Element(xn + "mgnSprdAmnt").Value,
mgnAddlAmnt = c.Element(xn + "mgnAddlAmnt").Value,
unadjMgnReq = c.Element(xn + "unadjMgnReq").Value
});
foreach (var x in myMarginRep)
Console.WriteLine(x);
Print:
CSLN
+222926.00
+0.00
+0.00
+89349.30
+312275.30
CSLM
+55112.00
+0.00
+0.00
+30854.40
+85966.40
Update:
Link: http://rextester.com/UFLPQ70590
You do need to do what JAT said in his post about changing the attributes to elements, but that isn't the reason why your list is not being created from the XML. It's the namespace ("xmlns="http://www.123456768.com/technology") that is giving you trouble. I'm not sure what your XML file is trying to accomplish by having it, but if you remove it and do what JAT recommended your IEnumerable will start to be populated.
For more information about namespaces, you can check out this link from w3:
http://www.w3schools.com/xml/xml_namespaces.asp

How to parse XML data into the properties of a custom C# class?

Setup
I have this in my Main() function.
List<Token> tokens = new List<Token>();
string path = #"\(some directories)\tokens.xml";
XDocument doc = XDocument.Load(path);
I have this class with a few properties.
public partial class Token
{
public Token()
{
SetURLs = new List<string>();
SetNames = new List<string>();
}
public string Name { get; set; }
public List<string> SetURLs { get; set; }
public List<string> SetNames { get; set; }
public string Color { get; set; }
public string PT { get; set; }
public string Text { get; set; }
}
I have this XML file. Here is a snippet.
<?xml version="1.0" encoding="UTF-8"?> //EDIT3
<card_database version="2"> //EDIT3
<cards>
.
.
.
<card>
<name>Griffin</name>
<set picURL="http://magiccards.info/extras/token/duel-decks-ajani-vs-nicol-bolas/griffin.jpg" picURLHq="" picURLSt="">DDH</set>
<color>w</color>
<manacost></manacost>
<type>Token</type>
<pt>2/2</pt>
<tablerow>0</tablerow>
<text>Flying</text>
<token>1</token>
</card>
<card>
<name>Rat</name>
<set picURL="http://magiccards.info/extras/token/shadowmoor/rat.jpg" picURLHq="" picURLSt="">SHM</set>
<set picURL="http://magiccards.info/extras/token/gatecrash/rat.jpg" picURLHq="" picURLSt="">GTC</set>
<color>b</color>
<manacost></manacost>
<type>Token</type>
<pt>1/1</pt>
<tablerow>0</tablerow>
<text></text>
<token>1</token>
</card>
.
.
.
</cards>
</card_database> //EDIT3
As you can see, there are many <card> elements in the <cards> root element. Further, each <card> can have many <set> elements. I made the class accordingly.
Problem
How do I go through one <card> at a time and assign the appropriate values to each property?
What I Have Tried
I made a list that contains all of the <name> elements of each <card>. I would then go through this list and assign a name to a new instance of the Token class's Name property. Then populate my tokens list with each new instance.
List<string> names = new List<string>();
names = doc.Descendants("card").Elements("name").Select(r => r.Value).ToList();
int amount = doc.Descendants("card").Count();
for(int i = 0; i < amount; i++)
{
Token token = new Token();
token.Name = name[i];
.
.
.
tokens.Add(token);
}
I guess I could then make more lists that contain every other desired element and do the same process, but there has to be a more elegant way, right?
EDIT
I also tried serialization from another question. But for some reason, when I tried to write something from token to the console (say token.Name), it didn't write anything.
XmlSerializer serializer = new XmlSerializer(typeof(Token));
using (StringReader reader = new StringReader(path))
{
Token token = (Token)(serializer.Deserialize(reader));
}
Probably just an incorrect implementation. If that is the case, could someone use what I posted and show me the correct implementation? Also, I assume this will give 1 or many values to my two List properties, right?
EDIT
Thanks for the help.
EDIT2
An Answer
After some unsuccessful fiddling with serialization and some more searching, I made an implementation that works.
foreach (var card in doc.Descendants("card"))
{
Token token = new Token();
token.Name = card.Element("name").Value.ToString();
foreach (var set in card.Elements("set"))
{
token.SetURLs.Add(set.Attribute("picURL").Value.ToString());
token.SetNames.Add(set.Value.ToString());
}
token.Color = card.Element("color").Value.ToString();
token.PT = card.Element("pt").Value.ToString();
token.Text = card.Element("text").Value.ToString();
tokens.Add(token);
}
Much better than the number of Lists I first had in mind. Not as succinct as the serialization might have been. However, it does what I need.
Thanks for the help.
EDIT4
Not sure if this many edits are allowed or against etiquette. Just wanted to make this edit for future readers.
The stuff under the "An Answer" section does solve my problem but the XML Serialization posted below by Dave is much better; it is more flexible and easier to reuse/modify. So, pick the solution that has more benefits for your situation.
Using XML Serialization I was able to deserialize your snippet into some objects. I don't really understand your 2 different list variables so i modified it into 1 list.
I am not sure if this is exactly what you are trying to pull off, but i believe it should help you with your xml deserialization of multiple "set" elements.
I created a file with your same snippet named tokens.xml, edited to match your new layout.
<?xml version="1.0" encoding="UTF-8"?>
<card_database version="2">
<cards>
<card>
<name>Griffin</name>
<set picURL="http://magiccards.info/extras/token/duel-decks-ajani-vs-nicol-bolas/griffin.jpg" picURLHq="" picURLSt="">DDH</set>
<color>w</color>
<manacost></manacost>
<type>Token</type>
<pt>2/2</pt>
<tablerow>0</tablerow>
<text>Flying</text>
<token>1</token>
</card>
<card>
<name>Rat</name>
<set picURL="http://magiccards.info/extras/token/shadowmoor/rat.jpg" picURLHq="" picURLSt="">SHM</set>
<set picURL="http://magiccards.info/extras/token/gatecrash/rat.jpg" picURLHq="" picURLSt="">GTC</set>
<color>b</color>
<manacost></manacost>
<type>Token</type>
<pt>1/1</pt>
<tablerow>0</tablerow>
<text></text>
<token>1</token>
</card>
</cards>
</card_database>
I created a few classes
[XmlRoot(ElementName = "card_database")]
public class CardsDatabase
{
public CardsDatabase()
{
}
[XmlElement(ElementName = "cards", Form = XmlSchemaForm.Unqualified)]
public CardsList Cards { get; set; }
[XmlAttribute(AttributeName = "version", Form = XmlSchemaForm.Unqualified)]
public string Version { get; set; }
}
[XmlRoot(ElementName = "cards")]
public class CardsList
{
public CardsList()
{
Cards = new List<Card>();
}
[XmlElement(ElementName = "card", Form = XmlSchemaForm.Unqualified)]
public List<Card> Cards { get; set; }
}
[XmlRoot(ElementName = "card")]
public class Card
{
public Card()
{
SetURLs = new List<SetItem>();
}
[XmlElement(ElementName = "name", Form = XmlSchemaForm.Unqualified)]
public string Name { get; set; }
[XmlElement(ElementName = "set", Form = XmlSchemaForm.Unqualified)]
public List<SetItem> SetURLs { get; set; }
[XmlElement(ElementName = "color", Form = XmlSchemaForm.Unqualified)]
public string Color { get; set; }
[XmlElement(ElementName = "pt", Form = XmlSchemaForm.Unqualified)]
public string PT { get; set; }
[XmlElement(ElementName = "text", Form = XmlSchemaForm.Unqualified)]
public string Text { get; set; }
}
[XmlRoot(ElementName = "set")]
public class SetItem
{
public SetItem()
{
}
[XmlAttribute(AttributeName = "picURL", Form = XmlSchemaForm.Unqualified)]
public string PicURL { get; set; }
[XmlAttribute(AttributeName = "picURLHq", Form = XmlSchemaForm.Unqualified)]
public string PicURLHq { get; set; }
[XmlAttribute(AttributeName = "picURLSt", Form = XmlSchemaForm.Unqualified)]
public string PicURLSt { get; set; }
[XmlText]
public string Value { get; set; }
}
The main body is as follows (I know this is ugly, but i was going fast so please improve)
CardsDatabase cards = new CardsDatabase();
string path = #"tokens.xml";
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlSerializer serializer = new XmlSerializer(typeof(CardsDatabase));
using (StringReader reader = new StringReader(doc.InnerXml))
{
cards = (CardsDatabase)(serializer.Deserialize(reader));
}
The following is what the output looked like.
With Linq to Xml,
string path = #"~/tokens.xml";
var doc = XDocument.Load(Server.MapPath(Url.Content(path)));
var cards = doc.Descendants("card")
.Select(x =>
new Token
{
Name = x.Element("name").Value,
SetURLs = x.Elements("set").Select(y => y.Attribute("picURL").Value)
.ToList(),
SetNames = x.Elements("set").Select(y => y.Value).ToList(),
Color = x.Element("color").Value,
PT = x.Element("pt").Value,
Text = x.Element("text").Value
}).ToList();
hope this helps.
Check out this post:
XPath and *.csproj
But take the below and convert the anonymous types to your concrete class(es).
It should be enough to get you started.
XDocument xDoc = /* populate from somewhere */
XNamespace nsPlaceHolder = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");
XNamespace ns = string.Empty;
var list1 = from list in xDoc.Descendants(ns + "cards")
from item in list.Elements(ns + "card")
/* where item.Element(ns + "card") != null */
select new
{
PicURL = item.Attribute("picURL").Value,
MyName = (item.Element(ns + "name") == null) ? string.Empty : item.Element(ns + "name").Value
};
foreach (var v in list1)
{
Console.WriteLine(v.ToString());
}

How to load XML Elements using LINQ from XDocument into a class (not using Descendants)

How to load XML Elements using LINQ from XDocument into a c# class. I don't want to use XDocument.Descendants because the settings are not repeated and occur only once in the XML.
This works but I think there must be another way where I don't have to use IEnumerable or use ToArray() and use the first element [0]. Any suggestions?
CODE
public class BackupItem // class needed so LINQ reads XML into an editable DbGrid
{
public bool Backup { get; set; }
public bool IncludeSubDir { get; set; }
public string BackupLabel { get; set; }
public string BackupPath { get; set; }
}
public class BackupSettings
{
public bool IncludeDateStamp { get; set; }
public bool DatePrefix { get; set; }
public bool DateSuffix { get; set; }
public string DateFormat { get; set; }
public bool ZipCompress { get; set; }
public bool ZipPrefix { get; set; }
public bool ZipSuffix { get; set; }
public string ZipText { get; set; }
public bool BackupToSiblingFolder { get; set; }
public string SiblingFolder { get; set; }
public bool BackupToFolder { get; set; }
public bool IncludeFullPath { get; set; }
public string BackupFolder { get; set; }
}
// use a LINQ query to load xml file into datagridview and make datagrid editable (create class with get/set)
var q = from arg in GvXMLDoc.Descendants("BackupItem")
select new BackupItem()
{
Backup = (bool)arg.Element("IncludeDirectory"),
IncludeSubDir = (bool)arg.Element("IncludeSubDirectories"),
BackupLabel = (string)arg.Element("BackupLabel"),
BackupPath = (string)arg.Element("BackupPath")
};
dataGridView1.DataSource = q.ToList();
// load global variable
IEnumerable<BackupSettings> GvBackupSettings = from arg in GvXMLDoc.Element("Backup").Elements("Settings")
select new BackupSettings()
{
IncludeDateStamp = (bool)arg.Element("IncludeDateStamp"),
DatePrefix = (bool)arg.Element("DatePrefix"),
DateSuffix = (bool)arg.Element("DateSuffix"),
DateFormat = (string)arg.Element("DateFormat"),
ZipCompress = (bool)arg.Element("ZipCompress"),
ZipPrefix = (bool)arg.Element("ZipPrefix"),
ZipSuffix = (bool)arg.Element("ZipSuffix"),
ZipText = (string)arg.Element("ZipText"),
BackupToSiblingFolder = (bool)arg.Element("BackupToSiblingFolder"),
SiblingFolder = (string)arg.Element("SiblingFolder"),
BackupToFolder = (bool)arg.Element("BackupToFolder"),
IncludeFullPath = (bool)arg.Element("IncludeFullPath"),
BackupFolder = (string)arg.Element("BackupFolder")
};
I can access the values but it seems a very 'messy way'.
var s = GvBackupSettings.ToArray()[0].DateSuffix;
var t = GvBackupSettings.ToArray()[0].DateFormat;
XML FILE
<?xml version='1.0'?>
<Backup>
<Settings>
<IncludeDateStamp>true</IncludeDateStamp>
<DatePrefix>false</DatePrefix>
<DateSuffix>true</DateSuffix>
<DateFormat>yyyy-MM-dd h.m.s</DateFormat>
<ZipCompress>false</ZipCompress>
<ZipPrefix>false</ZipPrefix>
<ZipSuffix>false</ZipSuffix>
<ZipText></ZipText>
<BackupToSiblingFolder>true</BackupToSiblingFolder>
<SiblingFolder>backups</SiblingFolder>
<BackupToFolder>false</BackupToFolder>
<IncludeFullPath>true</IncludeFullPath>
<BackupFolder>C:\\backup</BackupFolder>
</Settings>
<BackupItem>
<IncludeDirectory>true</IncludeDirectory>
<IncludeSubDirectories>true</IncludeSubDirectories>
<BackupLabel>Backup1</BackupLabel>
<BackupPath>C:\TestFiles\Xml\Samples</BackupPath>
</BackupItem>
<BackupItem>
<IncludeDirectory>true</IncludeDirectory>
<IncludeSubDirectories>false</IncludeSubDirectories>
<BackupLabel>Backup2</BackupLabel>
<BackupPath>C:\TestFiles\Xml\Samples</BackupPath>
</BackupItem>
</Backup>
EDIT 1
I also am trying to deserialize the XML (thanks for idea) so I don't have to cast each item. This does not work.. I don't want to have to run the XSD tool either and have a huge class file...
XmlRootAttribute rootAttribute = new XmlRootAttribute("Backup");
XmlSerializer deserializer = new XmlSerializer((typeof(BackupSettings)), rootAttribute);
GvBackupSettings = (BackupSettings)deserializer.Deserialize(XmlReader.Create(GvXMLFileName));
EDIT 2
Ended up serializing and deserializing xml as suggested below using stardard XSD.exe tool to generate the c# class. Especially as I had to read and write to same xml file. Note: Make sure you verify/modify the generated xsd file first.
You don't need a query if you just need the first element:
XElement settings = GvXMLDoc.Element("Backup").Element("Settings");
BackupSettings GvBackupSettings = new BackupSettings
{
IncludeDateStamp = (bool)settings.Element("IncludeDateStamp"),
DatePrefix = (bool)settings.Element("DatePrefix"),
...
};
var s = GvBackupSettings.DateSuffix;
var t = GvBackupSettings.DateFormat;

Get child element in another child element of XML

I have a XML file that goes like this... (the XML file was taken from web services [WCF] after passing some value into it.)
<Title>
<Questions>
<QuestionID> 1 </QuestionID>
<QuestionType> Quiz </QuestionType>
<Question> What is the shape? </Question>
<SubQuestionSequence> Part 1 </SubQuestionSequence>
<SubQuestions>
<Keywords> Ring </Keywords>
<ParentQuestionID> 1 </ParentQuestionID>
</SubQuestions>
<SubQuestionSequence> Part2 </SubQuestionSequence>
<SubQuestions>
<Keywords> Round </Keywords>
<ParentQuestionID> 1 </ParentQuestionID>
</SubQuestions>
</Questions>
</Title>
The methods to take child elements as below (written in C#), the commented area is supposed to call the class of subQuestion, but i'm not sure how to write that part :
public class Questions {
public int QuestionID { get; set; }
public string QuestionType { get; set; }
public string Question { get; set; }
public string SubQuestionSequence { get; set; }
//suppose to call subQuestion here
}
public class SubQuestion {
public string Keywords { get ; set ; }
public int ParentQuestionID { get; set; }
}
The actual code behind of the file, also the query area, i does not know how to call if they have another sub section:
void client_GetQuestionCompleted(object sender, GetQuestionCompletedEventArgs e)
{
if (e.Error != null)
return;
string result = e.Result.Nodes[0].ToString();
XDocument doc = XDocument.Parse(result);
var QuestionDetails = from Query in doc.Descendants("QuestionDetail")
select new Questions
{
QuestionID = (int)Query.Element("QuestionID"),
QuestionType = (string)Query.Element("QuestionType"),
Question = (string)Query.Element("Question"),
SubQuestionSequence = (string)Query.Element("SubQuestionSequence")
};
int z = 0;
foreach (var QuestionDetail in QuestionDetails)
{
qID = QuestionDetail.QuestionID;
qType = QuestionDetail.QuestionType;
quest = QuestionDetail.Question;
subQS = QuestionDetail.SubQuestionSequence;
z++;
}
}
As you can see from the top, how can i take the child elements of SubQuestions (The keywords and ParentQuestionID) where SubQuestion itself already is a child element ?
[edit] how can i retrieve the repeated element in the child element ? I want some part to loop and retrieve data, and some doesn't need to loop to retrieve.
int z = 0;
foreach (var QuestionDetail in QuestionDetails)
{
qID = QuestionDetail.QuestionID;
qType = QuestionDetail.QuestionType;
quest = QuestionDetail.Question;
subQS[z] = QuestionDetail.SubQuestionSequence;
//doing it this way, i can only retrieve one row of record only,
//even though i used an array to save.
subKeyword[z] = QuestionDetail.SubQuestion.Keywords;
z++;
}
As long as there is only a single SubQuestions element you can simply access Query.Element("SubQuestions").Element("Keywords") respectively Query.Element("SubQuestions").Element("ParentQuestionID").
[edit]
As for you class with an object of the type SubQuestion you would simply use
public class Questions {
public int QuestionID { get; set; }
public string QuestionType { get; set; }
public string Question { get; set; }
public string SubQuestionSequence { get; set; }
public SubQuestion SubQuestion{ get; set; }
}
public class SubQuestion {
public string Keywords { get ; set ; }
public int ParentQuestionID { get; set; }
}
and then in your query you can use e.g.
var QuestionDetails = from Query in doc.Descendants("QuestionDetail")
select new Questions
{
QuestionID = (int)Query.Element("QuestionID"),
QuestionType = (string)Query.Element("QuestionType"),
Question = (string)Query.Element("Question"),
SubQuestionSequence = (string)Query.Element("SubQuestionSequence"),
SubQuestion = new SubQuestion() {
Keywords = (string)Query.Element("SubQuestions").Element("Keywords"),
ParentQuestionID = (int)Query.Element("SubQuestions").Element("ParentQuestionID")
}
};

Categories