Read specific element from XElement - c#

I want to bind the MultipleCheckbox items from Choice Column of sharepoint List to asp.net CheckBoxListItem using c#. I am retriving information of List using XELEMENT as:
XElement listStructure;
listStructure = proxy.GetList("WebsiteSubscriber");
<Field Type="MultiChoice" DisplayName="Area" Required="FALSE" EnforceUniqueValues="FALSE" Indexed="FALSE" FillInChoice="FALSE" ID="{16cc1615-a490-44de-a870-c7ebe603e2cc}" SourceID="{2c8a80ea-38c5-48f7-9d7d-400d445a5e64}" StaticName="Area" Name="Area" ColName="ntext2" RowOrdinal="0">
<Default>Articles</Default>
<CHOICES>
<CHOICE>Articles</CHOICE>
<CHOICE>Websites</CHOICE>
<CHOICE>Books</CHOICE>
</CHOICES>
</Field>
I want to read choices from this XML. and get values only "Articles,Websites,Books"
Note: This XML may contain many sections with <choices> i want to fetech it by <fieldType> or the DisplayName="Area" attribute and get values in c#.

var xml = #"<Field Type=""MultiChoice"" DisplayName=""Area"" Required=""FALSE"" EnforceUniqueValues=""FALSE"" Indexed=""FALSE"" FillInChoice=""FALSE"" ID=""{16cc1615-a490-44de-a870-c7ebe603e2cc}"" SourceID=""{2c8a80ea-38c5-48f7-9d7d-400d445a5e64}"" StaticName=""Area"" Name=""Area"" ColName=""ntext2"" RowOrdinal=""0"">
<Default>Articles</Default>
<CHOICES>
<CHOICE>Articles</CHOICE>
<CHOICE>Websites</CHOICE>
<CHOICE>Books</CHOICE>
</CHOICES>
</Field>";
var doc = XDocument.Parse(xml);
XElement element =
doc.Descendants("Field")
.First(field => (string)field.Attribute("DisplayName") == "Area");
string[] result =
element.Descendants("CHOICE")
.Select(v => (string)v)
.ToArray();
Console.WriteLine(string.Join(Environment.NewLine, result));
prints:
Articles
Websites
Books

Try this:
var temp =
listStructure.Descendants("Field")
.Where(i => i.Attribute("DisplayName").Value == "Area")
.Select(i => i.Descendants("CHOICE")
.Select(j => j.Value)).ToList();
List<string> result = new List<string>();
foreach (IEnumerable<string> item in temp)
{
result.AddRange(item);
}
//result: Articles; Websites; Books

Related

Linq statement in C# to extract data from XElement

I have a List containing elements like this:
{<d:element m:type="SP.KeyValue" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<d:Key>Path</d:Key>
<d:Value>https://my.home.site.com</d:Value>
<d:ValueType>Edm.String</d:ValueType>
</d:element>}
I'd like help to discern the Linq statement required to extract only the "https://my.home.site.com" values from said List<>. The catch here is that we cannot only use the <d:Value> because only XElements in this list that has a <d:Key> value of Path, like in the example above, actually contain URLs in the <d:Value> key.
Does anyone know the magic Linq statement that would perform said data extract?
Assuming your data is coming from an XML file similar to this:
<?xml version="1.0"?>
<root xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<d:element m:type="SP.KeyValue">
<d:Key>Path</d:Key>
<d:Value>https://my.home.site.com</d:Value>
<d:ValueType>Edm.String</d:ValueType>
</d:element>
<d:element m:type="SP.KeyValue">
<d:Key>NotPath</d:Key>
<d:Value>https://my.home.site.com</d:Value>
<d:ValueType>Edm.String</d:ValueType>
</d:element>
</root>
The following code:
XElement root = XElement.Load("Some file");
List<string> urls;
//Query Syntax
urls = (from e in root.Elements(d + "element")
where e.Element(d + "Key").Value == "Path"
select e.Element(d + "Value").Value);
//Or
//Method Syntax
urls = (from e in root.Elements(d + "element")
where e.Element(d + "Key").Value == "Path"
select e.Element(d + "Value").Value).ToList();
Console.WriteLine(string.Join(",", urls));
Will result in (note that it ignores the "NotPath" key):
https://my.home.site.com
You can check out a live example here and check out this for more XElement information.
if you actually have a List of XElement:
var list = new List<XElement>(); //however you get your XElement collection
var values = list.Where(x => x.Elements().First(e => e.Name.LocalName == "Key").Value == "Path")
.Select(x => x.Elements().First(e => e.Name.LocalName == "Value").Value)
if you have an XDocument, you'd just modify the beginning of the query slightly.
I think that problem if with naespace declaration. Try this:
string xml = "<d:element m:type=\"SP.KeyValue\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\">"+
"<d:Key>Path</d:Key>"+
"<d:Value>https://my.home.site.com</d:Value>"+
"<d:ValueType>Edm.String</d:ValueType>"+
"</d:element>";
XDocument xmlObj = XDocument.Parse(xml);
XNamespace ns_d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
var result = xmlObj.Descendants(ns_d + "Value").Select(x => x.Value);

C# reading values of elements from an XML tree

I am trying to read some values of specific elements in an XML document, such as the values of <main><alpha>, <main><beta><epsilon> and <main><gama><delta>.
<?xml version="1.0" ?>
<main>
<alpha>One</alpha>
<beta>
<delta>DeltaValueFromBeta</delta>
<epsilon>EpsilonValueFromBeta</epsilon>
<phi>PhiValueFromBeta</phi>
</beta>
<gamma>
<delta>DeltaValueFromGamma</delta>
<epsilon>EpsilonValueFromGamma</epsilon>
<phi>PhiValueFromGamma</phi>
</gamma>
</main>
I can get the values using code like this:
XDocument doc = XDocument.Load("Sample.xml");
var quiz = from elements in doc.Elements("main").Elements("beta").Elements("epsilon")
select elements;
foreach (var item in quiz)
{
string sValue = (string) item.Value;
textBox1.AppendText(sValue);
}
Is there a more direct way to select the element values I need, without having to use a foreach loop?
Thanks
Nick
XPath is another option for direct access to a node. This reference may assist you.
How to get values from an XML file matching XPath query in C#
Edit to add to text box without foreach where result = XPath query result collection:
textbox1.AppendText(result.Select(x => x.Value));
XPath allows for dynamic path building a little easier than LINQ queries.
You can do it in your linq query:
var quiz = (from elements in doc.Elements("main").Elements("beta").Elements("epsilon")
select (string)elements).ToList();
It will give you value list.And you can append your text without using foreach:
StringBuilder sb = new StringBuilder();
var values = quiz.Select(x => sb.Append(x));
textBox1.AppendText(sb.ToString());
Or better way:
var text = doc.Descendants("epsilon")
.Select(x => (string)x)
.Aggregate((x,y) => x + y);
textBox1.AppendText(text)
textBox1.AppendText(quiz.Select(x => x.Value).Aggregate((s, s1) => s + s1));
Use the following so you do not have to use a foreach:
IEnumerable<string> values = quiz.Select(x => x.Value);
Or all in one:
IEnumerable<string> values = doc.Elements("main").Elements("beta").Elements("epsilon").Select(x => x.Value);
textBox1.AppendText(values.Aggregate((i, j) => i + j));

Get XML values from XML database string in C#

I’m trying to get the values of an xml snippet that is stored in my database but can’t seem to make it work. They are all coming back null... The xml looks like this:
<fields>
<field id="EmployeeID">1002240002</field>
<field id="JobType">Web Manager</field>
<field id="CompanyCode">R6297C</field>
</fields>
My Code, with the string from the database is below.
string xml = "<fields><field id=\"EmployeeID\">1002240002</field><field id=\"JobType\">Web Manager</field><field id=\"CompanyCode\"> R6297C </field></fields>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
var n = xmlDoc.GetElementById("EmployeeID ");
if (n != null)
{
var employeeId = xmlDoc.GetElementById("EmployeeID ").InnerText;
}
Any help on this? I know I am missing something easy here... Thanks!
You can use following XPath query
string xpath = "field[#id='EmployeeID']";
XmlNode fieldNode = xmlDoc.DocumentElement.SelectSingleNode(xpath);
var id = Int32.Parse(fieldNode.InnerText);
Or Linq to Xml
var id = (from f in xdoc.Descendants()
where (string)f.Attribute("id") == "EmployeeID"
select (int)f).Single();
Or with fluent interface
var id = xdoc.Descendants()
.Where(f => (string)f.Attribute("id") == "EmployeeID")
.Select(f => (int)f)
.Single();
BTW xdoc is an instance of XDocument class:
var xdoc = new XDocument(xml);

Filtering out duplicate XElements based on an attribute value from a Linq query

I'm using Linq to try to filter out any duplicate XElements that have the same value for the "name" attribute.
Original xml:
<foo>
<property name="John" value="Doe" id="1" />
<property name="Paul" value="Lee" id="1" />
<property name="Ken" value="Flow" id="1" />
<property name="Jane" value="Horace" id="1" />
<property name="Paul" value="Lee" id="1" />
... other xml properties with different id's
</foo>
// project elements in group into a new XElement
// (this is for another part of the code)
var props = group.data.Select( f => new XElement("property",
new XAttribute("name", f.Attribute("name").Value), f.Attribute("value"));
// filter out duplicates
props = props.Where(f => f.ElementsBeforeSelf()
.Where(g => g.Attribute("name").Value ==
f.Attribute("name").Value)
.Count() == 0);
Unfortunately, the filter step isnt working. I would think that Where() filter would check for any element before the current one that has the same property name and then include that in a set that was more than zero, thereby excluding the current element (called 'f'), but thats not happening. Thoughts ?
You could just create an IEqualityComparer to use with the Distinct(), that should get you what you need.
class Program
{
static void Main(string[] args)
{
string xml = "<foo><property name=\"John\" value=\"Doe\" id=\"1\"/><property name=\"Paul\" value=\"Lee\" id=\"1\"/><property name=\"Ken\" value=\"Flow\" id=\"1\"/><property name=\"Jane\" value=\"Horace\" id=\"1\"/><property name=\"Paul\" value=\"Lee\" id=\"1\"/></foo>";
XElement x = XElement.Parse(xml);
var a = x.Elements().Distinct(new MyComparer()).ToList();
}
}
class MyComparer : IEqualityComparer<XElement>
{
public bool Equals(XElement x, XElement y)
{
return x.Attribute("name").Value == y.Attribute("name").Value;
}
public int GetHashCode(XElement obj)
{
return obj.Attribute("name").Value.GetHashCode();
}
}
Your appoach is a bit weird, e.g., You don't need to project elements into new elements; it just works(tm) when you add existing elements to a new document.
I would simply group the <property> elements by the name attribute and then select the first element from each group:
var doc = XDocument.Parse(#"<foo>...</foo>");
var result = new XDocument(new XElement("foo",
from property in doc.Root
group property by (string)property.Attribute("name") into g
select g.First()));
I think you should remove the duplicates first, and then do your projection. For example:
var uniqueProps = from property in doc.Root
group property by (string)property.Attribute("name") into g
select g.First() into f
select new XElement("property",
new XAttribute("name", f.Attribute("name").Value),
f.Attribute("value"));
or, if you prefer method syntax,
var uniqueProps = doc.Root
.GroupBy(property => (string)property.Attribute("name"))
.Select(g => g.First())
.Select(f => new XElement("property",
new XAttribute("name", f.Attribute("name").Value),
f.Attribute("value")));

Reading Xml file using LINQ in C#

I have a list of String
List<String> lst=new List<String>{"A","B","C"}
And an xml file like
<Root>
<ChildList>
<Childs>
<Child Name="a1" Val="A"/>
<Child Name="a2" val="A"/>
<Child Name="b1" val="B"/>
</Childs>
</ChildList>
</Root>
i need to read contets of the xml file and add to a dictionary
Dictionary<String,List<String>> dict
where the dictionary key is the items in the "lst" and value is the attribute value of "Name" from the file
So the result will be like
Key(String) Value(List<String>)
"A" "a1","a2"
"B" "b1"
"C" null
now i'm using nested for loop for this
Is there any wau to do this using LINQ to XML
Thanks in advance
I think this will do it:
XDocument doc = XDocument.Load("foo.xml");
ILookup<string, string> lookup = doc.Descendants("Childs")
.First()
.Elements("Child")
.ToLookup(x => (string) x.Attribute("Val"),
x => (string) x.Attribute("Name"));
var dictionary = lst.ToDictionary(x => x,
x => lookup[x].ToList().NullIfEmpty());
Using a helper method:
public static List<T> NullIfEmpty<T>(this List<T> list)
{
return list.Count == 0 ? null : list;
}
If you don't mind having an empty list instead of null for items which aren't in the XML file, the second statement can be simplified, with no need for the helper method:
var dictionary = lst.ToDictionary(x => x, x => lookup[x].ToList());
Note that I've structured this so that it only needs to go through the XML file once, instead of searching through the file once for each element in the list.
var xml = #"<Root>
<ChildList>
<Childs>
<Child Name=""a1"" Val=""A""/>
<Child Name=""a2"" Val=""A""/>
<Child Name=""b1"" Val=""B""/>
</Childs>
</ChildList>
</Root>";
var lst= new List<String> { "A", "B", "C" };
var doc = XDocument.Parse(xml);
var dict = (from item in lst
select new
{
Key = item,
Value = (from elem in doc.Root.Element("ChildList").Element("Childs").Elements("Child")
where (string)elem.Attribute("Val") == item
select (string)elem.Attribute("Name")).ToList()
}).ToDictionary(i => i.Key, i => i.Value);
This can be made more efficient. I iterate over the elements once for every item in lst. I'll properly come up with another solution later if others don't come up with one.

Categories

Resources