Generating Xelement from list of object - c#

My Code
IList<Person> people=new List<Person>();
people.Add(new Person{Id=1,Name="Nitin"});
IList<decimal> my=new List<decimal>(){1,2,3};
IList<int> your=new List<int>(){1,2,3};
XElement xml = new XElement("people",
from p in people
select new XElement("person", new XAttribute("Id", "Hello"),
new XElement("id", p.Id),
new XElement("Mrp", my.Contains(1) ? string.Join(",",my):"Nitin"),
new XElement("Barcode", Form1.GetStrings(1).Select(i => new XElement("Barcode", i)))
));
MessageBox.Show(xml.ToString());
GetStrings only returns int from 1 to 4
Output
<people>
<person Id="Hello">
<id>1</id>
<Mrp>1,2,3</Mrp>
<Barcode>
<Barcode>1</Barcode>
<Barcode>2</Barcode>
<Barcode>3</Barcode>
<Barcode>4</Barcode>
</Barcode>
</person>
</people>
But I want output as
<people>
<person Id="Hello">
<id>1</id>
<Mrp>1,2,3</Mrp>
<Barcode>1</Barcode>
<Barcode>2</Barcode>
<Barcode>3</Barcode>
<Barcode>4</Barcode>
</person>
</people>
Any Solutions

Then instead of this:
new XElement("Barcode", Form1.GetStrings(1).Select(i => new XElement("Barcode", i)))
Use your query directly like this, don't create an extra Barcode element:
Form1.GetStrings(1).Select(i => new XElement("Barcode", i))
Then your code should look like this:
XElement xml = new XElement("people",
from p in people
select new XElement("person", new XAttribute("Id", "Hello"),
new XElement("id", p.Id),
new XElement("Mrp", my.Contains(1) ? string.Join(",",my):"Nitin"),
Form1.GetStrings(1).Select(i => new XElement("Barcode", i))
));
That will give you the expected output.

Try this :
XElement xml = new XElement("people",
from p in people
select new XElement("person", new XAttribute("Id", "Hello"),
new XElement("id", p.Id),
new XElement("Mrp", my.Contains(1) ? string.Join(",",my):"Nitin"),
Form1.GetStrings(1).Select(i => new XElement("Barcode", i))
));

Related

Conditionally adding a XElement to a new XElement using c~

I am trying to use XElement to add new content to an existing XML data file.
For the most part it is working OK but I need to change it. This is what I have so far:
xdoc.Root.Add(
new XElement("W" + record.Date.ToString("yyyyMMdd"),
new XElement("Chairman", historyItem.Chairman),
new XElement("AuxCounsellor1", historyItem.AuxCounsellor1),
new XElement("AuxCounsellor2", historyItem.AuxCounsellor2),
new XElement("VideoConferenceHost", string.Empty),
new XElement("VideoConferenceCohost", string.Empty),
new XElement("PrayerOpen", historyItem.PrayerOpen),
new XElement("PrayerClose", historyItem.PrayerClose),
new XElement("CBSConductor", historyItem.CBSConductor),
new XElement("CBSReader", historyItem.CBSReader),
new XElement("ReviewQuestion", string.Empty),
new XElement("Items",
new XAttribute("ItemCount", historyItem.TalkItems.Count),
new XElement("Item",
new XElement("Name", historyItem.TalkItems[0].Name),
new XElement("Theme", historyItem.TalkItems[0].Theme),
new XElement("Method", historyItem.TalkItems[0].Method)),
new XElement("Item",
new XElement("Name", historyItem.TalkItems[1].Name),
new XElement("Theme", historyItem.TalkItems[1].Theme),
new XElement("Method", historyItem.TalkItems[1].Method)),
new XElement("Item",
new XElement("Name", historyItem.TalkItems[2].Name),
new XElement("Theme", historyItem.TalkItems[2].Theme),
new XElement("Method", historyItem.TalkItems[2].Method)),
new XElement("Item",
new XElement("Name", historyItem.TalkItems[3].Name),
new XElement("Theme", historyItem.TalkItems[3].Theme),
new XElement("Method", historyItem.TalkItems[3].Method)),
new XElement("Item",
new XElement("Name", historyItem.TalkItems[4].Name),
new XElement("Theme", historyItem.TalkItems[4].Theme),
new XElement("Method", historyItem.TalkItems[4].Method)),
new XElement("Item",
new XElement("Name", historyItem.TalkItems[5].Name),
new XElement("Theme", historyItem.TalkItems[5].Theme),
new XElement("Method", historyItem.TalkItems[5].Method)))));
It creates an entry like this:
<W20220404>
<Chairman></Chairman>
<AuxCounsellor1></AuxCounsellor1>
<AuxCounsellor2></AuxCounsellor2>
<VideoConferenceHost></VideoConferenceHost>
<VideoConferenceCohost></VideoConferenceCohost>
<PrayerOpen></PrayerOpen>
<PrayerClose></PrayerClose>
<CBSConductor></CBSConductor>
<CBSReader></CBSReader>
<ReviewQuestion></ReviewQuestion>
<Items ItemCount="6">
<Item>
<Name></Name>
<Theme>“Come essere un vero amico”</Theme>
<Method>Talk</Method>
</Item>
<Item>
<Name></Name>
<Theme>Spiritual Gems</Theme>
<Method>Question and Answers</Method>
</Item>
<Item>
<Name></Name>
<Theme>Prepare This Month's Presentations</Theme>
<Method>Discussion with Video</Method>
</Item>
<Item>
<Name></Name>
<Theme>“Chi sono i tuoi amici online?”</Theme>
<Method>Discussion with Video</Method>
</Item>
<Item>
<Name></Name>
<Theme>Diamo il benvenuto agli ospiti</Theme>
<Method>Discussion with Video</Method>
</Item>
<Item>
<Name></Name>
<Theme></Theme>
<Method>Talk</Method>
</Item>
</Items>
</W20220404>
Now, I want to add another item into this W20220404 node, just after the list of Items. Eg:
<Teaching>
<Name Class="0">Brother 9</Name>
<Name Class="1">Brother 1</Name>
<Name Class="2">Brother 3</Name>
</Teaching>
But:
I only want to add the first Name if historyItem.Classes >= 1.
I only want to add the second Name if historyItem.Classes >= 2.
I only want to add the third Name if historyItem.Classes == 3.
I can't work out how to attach that. Initially I tried extending my code:
new XElement("Teaching",
new XElement("Name",
new XAttribute("Class", 0),
new XText(historyItem.Teaching[0])),
new XElement("Name",
new XAttribute("Class", 1),
new XText(historyItem.Teaching[1])),
new XElement("Name",
new XAttribute("Class", 2),
new XText(historyItem.Teaching[2])))));
But it doesn't factor in for the logical requirements. What is the sensible way to add this node using the rules indicated?
To summarize:
Create the Teaching node
if Teaching is not null
if historyItem.Classes >= 1
Add the first Name / attribute
if historyItem.Classes >= 2
Add the second Name / attribute
if historyItem.Classes == 3
Add the third Name / attribute
So if the Teaching element is null I want an empty Teaching element in XML.
Making sense?
You can take advantage of the fact that null nodes are ignored, so make a condition where you pass null when the condition is not met.
Here is the basic idea:
new XElement("Teaching",
historyItem.Classes >= 1 ? new XElement("Name",
new XAttribute("Class", 0),
new XText(historyItem.Teaching[0])) : null,
After reading the comment, it appears that you don't even need a conditional and could do the following:
historyItem.Teaching != null ? new XElement("Teaching",
new XElement("Name",
new XAttribute("Class", historyItem.Classes - 1),
new XText(historyItem.Teaching[historyItem.Classes - 1]))
), null));
I thought I would add this as an alternative to the initial answer which goes about things slightly differently. An alternative to using one large chain and factoring in the logic requirements for the Teaching node:
XElement historyWeek = new XElement("W" + record.Date.ToString("yyyyMMdd"));
if(historyItem.Meeting)
{
historyWeek.Add(new XElement("Chairman", historyItem.Chairman),
new XElement("AuxCounsellor1", historyItem.AuxCounsellor1),
new XElement("AuxCounsellor2", historyItem.AuxCounsellor2),
new XElement("VideoConferenceHost", string.Empty),
new XElement("VideoConferenceCohost", string.Empty),
new XElement("PrayerOpen", historyItem.PrayerOpen),
new XElement("PrayerClose", historyItem.PrayerClose),
new XElement("CBSConductor", historyItem.CBSConductor),
new XElement("CBSReader", historyItem.CBSReader),
new XElement("ReviewQuestion", string.Empty));
XElement historyTalkItems = new XElement("Items",
new XAttribute("ItemCount", historyItem.TalkItems.Count));
foreach (var talkItem in historyItem.TalkItems)
{
historyTalkItems.Add(new XElement("Item",
new XElement("Name", talkItem.Name),
new XElement("Theme", talkItem.Theme),
new XElement("Method", talkItem.Method)));
}
historyWeek.Add(historyTalkItems);
XElement historyTeaching = new XElement("Teaching");
if(historyItem.Teaching.Any())
{
for (int iClass = 0; iClass < historyItem.Classes; iClass++)
{
historyTeaching.Add(new XElement("Name",
new XAttribute("Class", iClass),
new XText(historyItem.Teaching[iClass])));
}
}
historyWeek.Add(historyTeaching);
}
xdoc.Root.Add(historyWeek);

LINQ to XML DOM (making a modifed Tree easily)

I'd like to delete the last element and put somthing else instead of it.
I made some imaginary codes (** IT IS NOT Working one**).
I want to re-use upper part of it, because they are too long and changing all the time.
How can I make real ones ?
Thanks !!
var orignalTREE = new XDocument(
new XElement( "Root", new XAttribute("Id", "0"),
new XElement( "One", new XAttribute("Id", "1"),
new XElement( "Two", new XAttribute("Id", "2"),
new XElement( "Three", new XAttribute("Id", "3"),
new XElement( "Four", new XAttribute("Id", "4"),
new XElement( "Five", new XAttribute("Id", "5"),
new XElement("Six", new XAttribute("Id", "6"),
new XElement("Seven", new XAttribute("Id", "7"),
new XElement( "LAST", "It will be removed")
)))))))));
var extractedELMNT = orignalTREE.ElementsBeforeSelf("LAST");
orignalTREE.Descendants("LAST").Remove();
var modifiedTREE = new XDocument(
new XElement(
extractedELMNT.Select(x =>x),
new XElement( "Modified", new XAttribute("Testing...")
)));
MessageBox.Show( "Removed\n\n" + orignalTREE.ToString() +"\n\n\n"+
"Recovered\n\n" + modifiedTREE.ToString());
[Add]
I'd like to change the result from This one;
<Root Id="0">
<One Id="1">
<Two Id="2">
<Three Id="3">
<Four Id="4">
<Five Id="5">
<Six Id="6">
<Seven Id="7">
<LAST>It will be removed</LAST>
</Seven>
</Six>
</Five>
</Four>
</Three>
</Two>
</One>
</Root>
to This one.
<Root Id="0">
<One Id="1">
<Two Id="2">
<Three Id="3">
<Four Id="4">
<Five Id="5">
<Six Id="6">
<Seven Id="7">
<Modified>Testing..</Modified>
</Seven>
</Six>
</Five>
</Four>
</Three>
</Two>
</One>
</Root>
In general ways.
try this:
Updated:
var orignalTREE = new XDocument(
new XElement("Root", new XAttribute("Id", "0"),
new XElement("One", new XAttribute("Id", "1"),
new XElement("Two", new XAttribute("Id", "2"),
new XElement("Three", new XAttribute("Id", "3"),
new XElement("Four", new XAttribute("Id", "4"),
new XElement("Five", new XAttribute("Id", "5"),
new XElement("Six", new XAttribute("Id", "6"),
new XElement("Seven", new XAttribute("Id", "7"),
new XElement("LAST", "It will be removed")
)))))))));
var modifiedTREE = new XDocument(orignalTREE);
var parent = modifiedTREE.Descendants("LAST").FirstOrDefault().Parent;
modifiedTREE.Descendants("LAST").Remove();
parent.Add(new XElement("Modified", "Its attribute"));
Console.WriteLine("Removed\n\n" + orignalTREE.ToString() + "\n\n\n" +
"Recovered\n\n" + modifiedTREE.ToString());

XElement with LINQ add node after specific node

I've got this XML:
<?xml version="1.0" encoding="utf-8"?>
<JMF SenderID="InkZone-Controller" Version="1.2">
<Command ID="cmd.00695" Type="Resource">
<ResourceCmdParams ResourceName="InkZoneProfile" JobID="K_41">
<InkZoneProfile ID="r0013" Class="Parameter" Locked="false" Status="Available" PartIDKeys="SignatureName SheetName Side Separation" DescriptiveName="Schieberwerte von DI" ZoneWidth="32">
<InkZoneProfile SignatureName="SIG1">
<InkZoneProfile Locked="False" SheetName="S1">
<InkZoneProfile Side="Front">
<ColorPool Class="Parameter" DescriptiveName="Colors for the job" Status="Available">
<InkZoneProfile Separation="PANTONE 647 C" ZoneSettingsX="0 0,003 " />
</ColorPool>
</InkZoneProfile>
</InkZoneProfile>
</InkZoneProfile>
</InkZoneProfile>
</ResourceCmdParams>
</Command>
</JMF>
I'm trying to add a node after a specific node() , using XElement and Linq. But my LINQ query always returns me null.
Tried this:
XElement InkZonePath = XmlDoc.Element("JMF").Elements("InkZoneProfile").Where(z => z.Element("InkZoneProfile").Attribute("Side").Value == "Front").SingleOrDefault();
And this:
XmlDoc.Element("JMF")
.Elements("InkZoneProfile").Where(InkZoneProfile => InkZoneProfile.Attribute("Side")
.Value == "Front").FirstOrDefault().AddAfterSelf(new XElement("InkZoneProfile",
new XAttribute("Separation", x.colorname),
new XAttribute("ZoneSettingsX", x.colorvalues)));
I've built this queries following those examples:
Select XElement where child element has a value
Insert XElements after a specific node
LINQ-to-XML XElement query NULL
But it didn't worked as expected. What is wrong with the LINQ Query ? From what i've read it should work (logically reading the expression i can understand it).
Thanks
EDIT-1: Entire writexml Method
public void writexml(xmldatalist XMLList, variables GlobalVars)
{
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true,
IndentChars = "\t",
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Replace,
Encoding = new UTF8Encoding(false)
};
string DesktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
string FileExtension = ".xml";
string PathString = Path.Combine(DesktopFolder, "XML");
System.IO.Directory.CreateDirectory(PathString);
foreach (List<xmldata> i in XMLList.XMLArrayList)
{
int m = 0;
foreach (var x in i)
{
string XMLFilename = System.IO.Path.GetFileNameWithoutExtension(x.xml_filename);
GlobalVars.FullPath = Path.Combine(PathString, XMLFilename + FileExtension);
if (!File.Exists(GlobalVars.FullPath))
{
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("JMF",
new XAttribute("SenderID", "InkZone-Controller"),
new XAttribute("Version", "1.2"),
new XElement("Command",
new XAttribute("ID", "cmd.00695"),
new XAttribute("Type", "Resource"),
new XElement("ResourceCmdParams",
new XAttribute("ResourceName", "InkZoneProfile"),
new XAttribute("JobID", "K_41"),
new XElement("InkZoneProfile",
new XAttribute("ID", "r0013"),
new XAttribute("Class", "Parameter"),
new XAttribute("Locked", "False"),
new XAttribute("Status", "Available"),
new XAttribute("PartIDKeys", "SignatureName SheetName Side Separation"),
new XAttribute("DescriptiveName", "Schieberwerte von DI"),
new XAttribute("ZoneWidth", "32"),
new XElement("InkZoneProfile",
new XAttribute("SignatureName", "SIG1"),
new XElement("InkZoneProfile",
new XAttribute("Locked", "false"),
new XAttribute("SheetName", "S1"),
new XElement("InkZoneProfile",
new XAttribute("Side", "Front"),
new XElement("ColorPoolClass",
new XAttribute("Class", "Parameter"),
new XAttribute("DescriptiveName", "Colors for the job"),
new XAttribute("Status", "Available")
)))))))));
doc.Save(GlobalVars.FullPath);
XDocument XmlDoc = new XDocument();
XmlDoc = XDocument.Load(GlobalVars.FullPath);
XElement InkZonePath = XmlDoc.Root.Descendants("InkZoneProfile").Where(z => (string)z.Attribute("Side") == "Front").SingleOrDefault();
if (InkZonePath != null)
{
InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
new XAttribute("Separation", x.colorname),
new XAttribute("ZoneSettingsX", x.colorvalues)));
}
XmlDoc.Save(GlobalVars.FullPath);
}//Closing !FileExists
}//Closing inner foreach
}//Closing outer foreach
}//Closing writexml method
The problem with your current code is here : Element("JMF").Elements("InkZoneProfile") Since InkZoneProfile is not a direct child of JMF it will not return anything. Use Descendants instead.
Check difference between Elements & Descendants.
This should give you correct result:-
XElement InkZonePath = xdoc.Element("JMF").Descendants("InkZoneProfile")
.SingleOrDefault(z => (string)z.Attribute("Side") == "Front")
After this you can add whatever node you want to add using AddAfterSelf. Also note I have used SingleOrDefault here, but you may get exception if you have multiple matching nodes with this, In that case consider using FirstOrDefault.
Update:
To add new node:-
if (InkZonePath != null)
{
InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
new XAttribute("Separation", "Test"),
new XAttribute("ZoneSettingsX", "Test2")));
}
//Save XDocument
xdoc.Save(#"C:\Foo.xml");
You need to use Descendants method instead Elements:
XElement InkZonePath = XmlDoc.Root.Descendants("InkZoneProfile").Where(z => (string)z.Attribute("Side") == "Front").SingleOrDefault();
if(InkZonePath !=null)
InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
new XAttribute("Separation", x.colorname),
new XAttribute("ZoneSettingsX", x.colorvalues)));
you can use Descendants instead.
var node = XmlDoc.Descendants("InkZoneProfile").Where(x=> x.Attribute("Side") !=null && x.Attribute("Side").Value == "Front").FirstorDefault();

how to display right xml format

I am trying to create an xml doc with a prefix g:
c#
static void Main(string[] args)
{
XNamespace g = "g:";
XElement contacts =
new XElement("Contacts",
new XElement("Contact",
new XElement( g+"Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144"),
new XElement("Address",
new XElement("street","this street"))
)
);
Console.WriteLine(contacts);
}
instead it shows up with:
..<contacts>
<contact>
<name xmlns="g:">
...
XNamespace g = "http://somewhere.com";
XElement contacts =
new XElement("Contacts", new XAttribute(XNamespace.Xmlns + "g", g),
new XElement("Contact",
new XElement( g+"Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144"),
new XElement("Address",
new XElement("street","this street"))
)
);
OUTPUT :
<Contacts xmlns:g="http://somewhere.com">
<Contact>
<g:Name>Patrick Hines</g:Name>
<Phone>206-555-0144</Phone>
<Address>
<street>this street</street>
</Address>
</Contact>
</Contacts>
Your code is working fine for me (output is):
<Contacts>
<Contact>
<Name xmlns="g:">Patrick Hines</Name>
<Phone>206-555-0144</Phone>
<Address>
<street>this street</street>
</Address>
</Contact>
</Contacts>
if you still can not get the correct output then you can try this:
new XDocument(
new XElement("Contacts",
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144"),
new XElement("Address",
new XElement("street","this street"))
)
)
).Save("foo.xml");
XDocument is in System.Xml.Linq namespace. So, at the top of your code file, add:
using System.Xml.Linq;
Then you can write the data to your file the following way:
XDocument doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
new System.Xml.Linq.XElement("Contacts"),
new XElement("Contact",
new XElement("Name", c.FirstOrDefault().DisplayName),
new XElement("PhoneNumber", c.FirstOrDefault().PhoneNumber.ToString()),
new XElement("Email", "abc#abc.com"));
doc.Save(...);

Save a Dictionary<int, List<Object>> data to XML file using LINQ

I want to write a Dictionary<int, List<Object>> data to XML file. I tried below code:
Dictionary<int, List<Author>> _empdata = new Dictionary<int, List<Author>>();
List<Author> _author1 = new List<Author> { new Author() { id = 1, name = "Tom", age = 25 } };
List<Author> _author2 = new List<Author> { new Author() { id = 2, name = "Jerry", age = 15 } };
_empdata.Add(1, _author1);
_empdata.Add(2, _author2);
string fileName = "Author_" + string.Format("{0:yyyy-MM-dd_hh-mm-ss-tt}", DateTime.Now);
string filePath = Path.Combine(Directory.GetCurrentDirectory(), fileName) + ".xml";
XElement elem = new XElement("StackOverflow");
foreach (KeyValuePair<int,List<Author>> pair in _empdata)
{
elem = new XElement("AUTHORDATA",
from item in pair.Value
select new XElement("AUTHOR",
new XElement("ID", item.id),
new XElement("NAME", item.name),
new XElement("AGE", item.age)
));
}
elem.Save(filePath);
My expected output is:
<AUTHORDATA>
<AUTHOR>
<ID>1</ID>
<NAME>Tom</NAME>
<AGE>25</AGE>
</AUTHOR>
<AUTHOR>
<ID>2</ID>
<NAME>Jerry</NAME>
<AGE>15</AGE>
</AUTHOR>
</AUTHORDATA>
But,I am getting below records in XML file:
<AUTHORDATA>
<AUTHOR>
<ID>2</ID>
<NAME>Jerry</NAME>
<AGE>15</AGE>
</AUTHOR>
</AUTHORDATA>
It is only writing the last List record in XML file every time. How can I fix this ? Note: The format of the XML file will be like above.
Any help is appreciated.
[EDIT] Awww sorry, I was misunderstanding your request:
XElement ad = new XElement("AUTHORDATA");
XElement elem = new XElement("StackOverflow", ad);
foreach (KeyValuePair<int, List<Author>> pair in _empdata)
{
ad.Add(new XElement("AUTHORDATA",
from item in pair.Value
select new XElement("AUTHOR",
new XElement("ID", item.id),
new XElement("NAME", item.name),
new XElement("AGE", item.age)
));
}
elem.Save(filePath);
You need to add node created in loop to AUTHORDATA node:
var authorData = new XElement("AUTHORDATA");
var root = new XElement("StackOverflow", authorData);
foreach (KeyValuePair<int,List<Author>> pair in _empdata)
{
authorData.Add(
from item in pair.Value
select new XElement("AUTHOR",
new XElement("ID", item.id),
new XElement("NAME", item.name),
new XElement("AGE", item.age)
));
}
root.Save(filePath);

Categories

Resources