C# XDocument - Get value of an attribute in an XML file [duplicate] - c#

This question already has answers here:
How to get attribute in the XDocument object
(2 answers)
Closed 4 years ago.
Here is my code so far:
XDocument document = XDocument.Load("C:\\modinfo.xml");
var elements = from r in document.Descendants("Mod")
select new
{
Author = r.Element("Author").Value,
Description = r.Element("Description").Value
};
foreach (var r in elements)
{
Console.WriteLine("AUTHOR = " + r.Author + Environment.NewLine + "DESCRIPTION = " + r.Description);
}
And this is my "modinfo.xml" file:
<Mod Name="Mod Name">
<Author>Author Name</Author>
<Description>Description Text</Description>
</Mod>
At the moment, it looks like
when I run the application. What I am trying to do is for it to also print "Mod Name" in it also.

Just select the Mod Name in your anonymous type:
var elements = from r in document.Descendants("Mod")
select new
{
ModName = r.Attribute("Name").Value,
Author = r.Element("Author").Value,
Description = r.Element("Description").Value
};
foreach (var r in elements)
{
Console.WriteLine("MOD Name = " + r.ModName + Environment.NewLine + "AUTHOR = " + r.Author + Environment.NewLine + "DESCRIPTION = " + r.Description);
}

If this is your complete xml, following should help you as you do not have multiple Mods.
XElement xmlTree = XElement.Parse(str);
var result = new {
Author = xmlTree.Element("Author").Value,
Description = xmlTree.Element("Description").Value,
Name =xmlTree.Attribute("Name").Value
};
Input
<Mod Name="Mod Name">
<Author>Author Name</Author>
<Description>Description Text</Description>
</Mod>
Output
Author : Author Name
Description : Description Text
Name :Mod Name

Related

Convert List to JSON Array [duplicate]

This question already has answers here:
Deserialize JSON with C#
(10 answers)
How can I deserialize JSON with C#?
(19 answers)
Closed 8 months ago.
I am looking for a way to convert the following manually typed JSON list to a List I can load, but still output the same format in C#, so in can be POSTed to a REST API.
var accs = #"{
" + "\n" +
#" ""Cities"": [
" + "\n" +
#" ""Atlanta"",
" + "\n" +
#" ""Chicago"",
" + "\n" +
#" ""San Diego""
" + "\n" +
#" ]
" + "\n" +
#"}
" + "\n" +
#"";
Assuming this is your model:
public class State
{
public List<string> Cities { get; set; }
public State(List<string> cities)
{
Cities = cities;
}
}
This is how you serialize and deserialize:
using System.Text.Json;
var listOfCities = new List<string>() { "Atlanta", "Chicago", "San Diego"};
var state = new State(listOfCities);
//Serialize
var jsonArray = JsonSerializer.Serialize(state);
// Deserialize
var obj = JsonSerializer.Deserialize<State>(jsonArray);
When you use #", you can avoid the + concatenation like:
var accs = #"
{
'Cities': [
'Atlanta',
'Chicago',
'San Diego'
]
}
";
You'll need to use ' (single quotes) instead of " in your JSON text, otherwise you have to escape \" them.
you don't need any custom classes, you can just parse your json string
using Newtonsoft.Json;
var jsonParsed=JObject.Parse(accs);
if you need list of cities as c# instance
List<string> cities =jsonParsed["Cities"].ToObject<List<string>>();
if you need just a well formatted json string
accs = jsonParsed.ToString();
result
{
"Cities": [
"Atlanta",
"Chicago",
"San Diego"
]
}

Discord.Net how to go to the next line in an embed with text formatting?

I've been looking for this but I cannot seem to find the answer.
What I want to accomplish is the following:
Right now when I reply with my embed it shows for example:
footbal,baseball
But what I want it to be is the following:
football,
baseball
Spread over 2 different lines.
Does anyone know how to do this with text Code?
Thank you in advance
Here is the code:
var value = "";
int price = 0;
foreach (var Item in content)
{
value += Item.Item1 + ": " + Item.Item2.ToString();
price += Item.Item2;
}
return new EmbedFieldBuilder()
{
Name = category + " - " + price,
Value = value
};
Worked for me with simple "\n" or Environment.NewLine:
var embed = new EmbedBuilder
{
Author = new EmbedAuthorBuilder() { Name = "AuthorNameHere" },
Title = "Sports",
Color = Color.Orange,
Description = "Football" + "\n\n" + "Baseball"
}.Build();
//var channel = GetYourNeededChannel();
await channel.SendMessageAsync("", false, embed);
Also works with fields in embed:
Fields = new List<EmbedFieldBuilder>()
{
new EmbedFieldBuilder()
{
Name = "TestField1",
Value = "FieldValue1" + "\n\n" + "FieldValue2"
}
}

c# List inside list XML Linq

I have the following statement
xdoc.Descendants("Father").Select(p => new
{
Son1 = (string)p.Element("Son1").Value,
Son2 = (string)p.Element("Son2").Value,
Son3= (string)p.Element("Son3").Value,
Son4 = (string)p.Element("Son4").Value,
Son5 = (string)p.Element("Son5").Value
}).ToList().ForEach(p =>
{
Response.Write("Son1= " + p.Son1 + " ");
Response.Write("Son2=" + p.Son2 + " ");
Response.Write("Son3=" + p.Son3 + " ");
Response.Write(("Son4 =") + p.Son4 + " ");
Response.Write(("Son5 =") + p.Son5 + " ");
Response.Write("<br />");
});
and it works fine as long as i have only one instance of each son , the problem is that i have multiple instances of Son5, and i donĀ“t know how to put Son5 inside of a list
Here is my XML code Example:
If you have several elements of same type, then you should parse them to list or other collection:
var fathers = from f in xdoc.Descendants("Father")
select new {
Son1 = (string)f.Element("Son1"),
Son2 = (string)f.Element("Son2"),
Son3= (string)f.Element("Son3"),
Son4 = (string)f.Element("Son4"),
Son5 = f.Elements("Son5").Select(s5 => (string)s5).ToList()
};
Some notes:
Don't use .Value of XElement or XAttribute - you can cast element itself to appropriate data type without accessing its value. Benefits - less code, more reliable in case element is missing (you will not get NullReferenceException)
Consider to use int or int? as elemenent values if your elements contain integer values
If you have single Father element, then don't work with collection of fathers. Just get xml root and check whether it's null or not. After that you can create single father object.
Writing response
foreach(var father in fathers)
{
Response.Write($"Son1={father.Son1} ");
Response.Write($"Son2={father.Son2} ");
Response.Write($"Son3={father.Son3} ");
Response.Write($"Son4={father.Son4} ");
Response.Write(String.Join(" ", father.Son5.Select(son5 => $"Son5={son5}"));
Response.Write("<br />");
}
Try this:
xdoc.Descendants("Father").Select(p => new
{
Son1 = p.Element("Son1").Value,
Son2 = p.Element("Son2").Value,
Son3= p.Element("Son3").Value,
Son4 = p.Element("Son4").Value,
Sons5 = p.Elements("Son5").Select(element => element.Value).ToList()
}).ToList().ForEach(p =>
{
Response.Write("Son1= " + p.Son1 + " ");
Response.Write("Son2=" + p.Son2 + " ");
Response.Write("Son3=" + p.Son3 + " ");
Response.Write("Son4 =" + p.Son4 + " ");
p.Sons5.ForEach(son5 => Response.Write("Son5 =" + son5 + " "));
Response.Write("<br />");
});
That will create a list of Son5 within your list of items, which you can iterate in the ForEach with another ForEach.

getting a specific value using linq to xml

I'm working on windows 8 metro apps and i need to get some information from a XML file.
i parse it with LINQ to XML but I've got a problem.
here is the XML:
<feed xmlns="http://www.allocine.net/v6/ns/">
<page>1</page>
<count>1</count>
<results type="movie">10</results>
<results type="person">0</results>
<totalResults>10</totalResults>
<movie code="61282">
<originalTitle>Avatar</originalTitle>
<title>Avatar</title>
<productionYear>2009</productionYear>
<release>
<releaseDate>2010-09-01</releaseDate>
</release>
<castingShort>
<directors>James Cameron</directors>
<actors>Sam Worthington, Zoe Saldana, Sigourney Weaver, Stephen Lang, Michelle Rodriguez</actors>
</castingShort>
<statistics>
<pressRating>4.33333</pressRating>
<userRating>4.31338</userRating>
</statistics>
<poster path="/medias/nmedia/18/78/95/70/19485155.jpg"
href="http://images.allocine.fr/medias/nmedia/18/78/95/70/19485155.jpg"/>
<linkList>
<link rel="aco:web"
href="http://www.allocine.fr/film/fichefilm_gen_cfilm=61282.html"/>
</linkList>
</movie>
</feed>
I need to get "code" value of the "movie" node and the "href" value of the node "link" but all the things i tried failed ...
You can consider that the beginning of the XML is <movie> because I get the file and i parse it to keep the XML clean as I want. my file start with <movie code="">
For a classic value like "actors" i do :
Actors = (string)query.Element("castingShort").Element("actors")
It is working perfectly! My problem is for the specific value with a name.
edit :
that's what i did with your advices.
var group1 = new SampleDataGroup("Group-1", "Films", "", "Assets/icone_groupe_all_movies.jpg", "Films sur le DD");
movieName = "avatar";
Uri = "http://api.allocine.fr/rest/v3/search?partner=YW5kcm9pZC12M3M&filter=movie,person&count=1&page=1&q=" + movieName + "&format=xml";
var httpResponse = await new HttpClient().GetAsync(Uri);
string sourceCode = get_new_xml(await httpResponse.Content.ReadAsStringAsync());
XDocument doc = XDocument.Parse(sourceCode);
XNamespace ns = "http://www.allocine.net/v6/ns/";
XElement movie = doc.Root.Element(ns + "movie");
XElement castingShort = movie.Element(ns + "castingShort");
XElement statistics = movie.Element(ns + "statistics");
Data data = new Data
{
MovieCode = (string)movie.Attribute("code"),
OriginalTitle = (string)movie.Element(ns + "originalTitle"),
Title = (string)movie.Element(ns + "title"),
ProductionYear = (string)movie.Element(ns + "productionYear"),
Directors = (string)castingShort.Element(ns + "directors"),
Actors = (string)castingShort.Element(ns + "actors"),
PressRating = (string)statistics.Element(ns + "pressRating"),
UserRating = (string)statistics.Element(ns + "userRating"),
Cover = (string)movie.Element(ns + "linkList").Element(ns + "link").Attribute("href")
};
group1.Items.Add(new SampleDataItem("Group-1-Item-1", data.Title, data.Cover, data.ProductionYear, "", data.ReleaseDate, group1));
this.AllGroups.Add(group1);
but unfortunately it still doesent work ...
Thus you have namespace declared in your xml, you should declare and initialize an XNamespace object, and to use it when specifying XName objects (arguments to Element methods):
XDocument xdoc = XDocument.Load(path_to_xml);
XNamespace ns = "http://www.allocine.net/v6/ns/";
XElement movie = xdoc.Root.Element(ns + "movie");
var code = (int)movie.Attribute("code");
var href = (string)movie.Element(ns + "linkList")
.Element(ns + "link").Attribute("href");
If you have only one <movie> element, then you don't need to operate on sequence of movie elements and treat single movie as list. Simply get movie node and create new data object via parsing that node:
XNamespace ns = "http://www.allocine.net/v6/ns/";
XElement movie = xdoc.Root.Element(ns + "movie");
XElement castingShort = movie.Element(ns + "castingShort");
XElement statistics = movie.Element(ns + "statistics");
Data data = new Data
{
MovieCode = (int)movie.Attribute("code"),
OriginalTitle = (string)movie.Element(ns + "originalTitle"),
Title = (string)movie.Element(ns + "title"),
ProductionYear = (string)movie.Element(ns + "productionYear"),
Directors = (string)castingShort.Element(ns + "directors"),
Actors = (string)castingShort.Element(ns + "actors"),
PressRating = (string)statistics.Element(ns + "pressRating"),
UserRating = (string)statistics.Element(ns + "userRating"),
Cover = (string)movie.Element(ns + "linkList")
.Element(ns + "link").Attribute("href")
};

LINQ to XML without knowing the nodes

I have this LINQ query:
XNamespace ns = NAMESPACE;
var items = (from c in doc.Descendants(ns +"Item")
select new Item
{
Title = c.Element(ns + "ItemAttributes").Element(ns + "Title").Value,
MFR = c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value,
Offer = c.Element(ns + "Offers").Element(ns + "TotalOffers").Value,
Amazon = c.Element(ns + "Offer").Element(ns + "Merchant").Elements(ns + "MerchantId"),
LowPrice = Convert.ToDouble(c.Element(ns + "FormattedPrice").Value),
SalesRank = Convert.ToInt32(c.Element(ns +"SalesRank").Value),
ASIN = c.Element(ns + "ASIN").Value
}).ToList<Item>();
It works great expect for when a node is not present. For example it my not have a MFR or a sales rank. How can I make it so if it does not have the node in question, it gives me a default value or at the very doesn't make me try catch my whole query for one item.
As far as I'm aware LINQ to XML doesn't support this. However I ran into this same mess in a project I was working on and created this extension for XElement to allow it. Maybe it could work for you:
public static XElement ElementOrDummy(this XElement parentElement,
XName name,
bool ignoreCase)
{
XElement existingElement = null;
if (ignoreCase)
{
string sName = name.LocalName.ToLower();
foreach (var child in parentElement.Elements())
{
if (child.Name.LocalName.ToLower() == sName)
{
existingElement = child;
break;
}
}
}
else
existingElement = parentElement.Element(name);
if (existingElement == null)
existingElement = new XElement(name, string.Empty);
return existingElement;
}
Basically it just checks to see if the element exists and if it doesn't it returns one with the same name and an empty value.
You can use XElement Explicit Conversion, e.g.:
(int?)c.Element(ns +"SalesRank")
Reference: http://msdn.microsoft.com/en-us/library/bb340386.aspx
if the problem that the XElement exists, but the value is blank? i.e.
<Item>
<ItemAttributes>
<Manufacturer></Manufacturer>
</ItemAttributes>
</Item>
then you can use the string.IsNullOrEmpty function
XNamespace ns = NAMESPACE;
var items = (from c in doc.Descendants(ns +"Item")
select new Item
{
MFR = if (string.IsNullOrEmpty(c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value)) ? "default value here" : c.Element(ns + "ItemAttributes").Element(ns + "Manufacturer").Value,
// omitted for brevity
}).ToList<Item>();

Categories