Get all attributes in XML - c#

I have an XML like this:
<msg action="getDetails" class="2">
<stamps msgtime="4/15/2014" ltq="2014-04-15">
<dat la="get" />
</stamps>
</msg>
How can I retrieve Dictionary of all the attributes and their corresponding values? The expected output should look this:
action - getDetails
class - 2
msgtime - 4/15/2014
ltq - 2014-04-15
la - get
I can get it work for a particular level, but not for all child elements.

var xDoc = XDocument.Load("path");
var attributes = xDoc.Descendants()
.SelectMany(x => x.Attributes())
.ToDictionary(x => x.Name.LocalName, x => (string)x);

Have you tried using Descendants?
It would allow you to get an IEnumerable<XElement> of all of the elements, getting the attributes is something you have already done it looks like.

Use Linq-to-XML it is much easier to get the attribute and their values.
Sample usage
XElement cust = new XElement("PhoneNumbers",
new XElement("Phone",
new XAttribute("type", "home"),
"555-555-5555"),
new XElement("Phone",
new XAttribute("type", "work"),
"555-555-6666")
);
IEnumerable<XElement> elList =
from el in cust.Descendants("Phone")
select el;
foreach (XElement el in elList)
Console.WriteLine((string)el.Attribute("type"));

Related

Getting XML node based on text value, that ends with XML

I have this xml document, where I want to read documenturl where innertext ends with .xml
<Root>
<hits>
<total>4</total>
<max_score />
<hits>
<_index>offentliggoerelser-prod-20161006</_index>
<_type>offentliggoerelse</_type>
<_id>urn:ofk:oid:23640715</_id>
<_score />
<_source>
<dokumenter>
<dokumentUrl>url.pdf</dokumentUrl>
<dokumentMimeType>application/pdf</dokumentMimeType>
<dokumentType>KONCERNREGNSKAB_FOR_OVERLIGGENDE_MODER</dokumentType>
</dokumenter>
<dokumenter>
<dokumentUrl>url.xml</dokumentUrl>
<dokumentMimeType>application/xml</dokumentMimeType>
<dokumentType>AARSRAPPORT</dokumentType>
</dokumenter>
<dokumenter>
<dokumentUrl>url.pdf</dokumentUrl>
<dokumentMimeType>application/pdf</dokumentMimeType>
<dokumentType>AARSRAPPORT</dokumentType>
</dokumenter>
</_source>
<sort>1490355849989</sort>
</hits>
</hits>
</Root>
I am trying to read dokumentUrl that ends with '.xml' only.
I try to use LINQ
XDocument mydoc = XDocument.Load(file);
XDocument xPlatformXml = new XDocument(mydoc);
XElement xel = xPlatformXml.Element("_source")
.Elements("dokumenter")
.Where(x => x.Element("dokumentUrl").Value == ".xml")
.SingleOrDefault();
but it does not work, can anyone pls help me
You can check if you have the descendants node that has value ends with .xml
XDocument mydoc = XDocument.Load(file);
XDocument xPlatformXml = new XDocument(mydoc);
XElement xel = xPlatformXml.Root.Descendants()
.Where(x => x.Name == "dokumentUrl" && x.Value.EndsWith(".xml"))
.SingleOrDefault();
Try this:
XDocument xPlatformXml = new XDocument(mydoc);
XElement xel = xPlatformXml.Element("_source")
.Elements("dokumenter")
.Where(x => x.Element("dokumentUrl").Value.EndsWith(".xml"))
.SingleOrDefault();
When using the Element method you must specify the entire path from the document root to the desired nodes. For example:
var xel = xPlatformXml.Element("Root")
.Element("hits")
.Element("hits")
.Element("_source")
.Elements("dokumenter")
.Elements("dokumentUrl")
.SingleOrDefault(x => x.Value.EndsWith(".xml"));
Or you can use the Descendants method. It is more concise, but may affect performance.
var xel2 = xPlatformXml.Descendants("dokumentUrl")
.SingleOrDefault(x => x.Value.EndsWith(".xml"));

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);

Can't remove all elements that share same attribute value in XML

I want to remove all elements that have the same name in one go. My current method removes one at a time even if I have more than one element with the same name.
XDocument doc = XDocument.Load("D:\\test.xml");
var course = new XElement("Course",
new XAttribute("Name", cname),
new XAttribute("Code", ccode),
new XAttribute("Length", clenght));
doc.Element("Departments").Element("Department1").Add(course);
doc.Save("D:\\test.xml");
This is my current remove code:
string sss is the text a get from a textbox.
remove(string sss)
XDocument doc = XDocument.Load("D:\\test.xml");
IEnumerable<XElement> elList =
from el in doc.Descendants("Deparment1").Elements("Course")
where el.Attribute("Name").Value == sss
select el;
// this should filter elements with same name attribute value
foreach (XElement el in elList)
{
el.Remove();
doc.Save("D:\\test.xml");
}
// this should remove them all and update the xml file
#Andrei V it doesn't change if I put the doc.save outside the foreach
doc.Descendants("Deparment1").Elements("Course")
.Where(el=>el.Attribute("Name").Value == sss)
.Remove();

Looping through xmlnodes using Xdocument

I have an xml string like this
<Test>
<ConnectionParameters>
<ConnectionParameter DisplayName="asd" Id="cgfh" IsPassword="false" IsRequired="true"> </ConnectionParameter>
<ConnectionParameter DisplayName="asdasd" Id="fgh" IsPassword="false" IsRequired="true"></ConnectionParameter>
<ConnectionParameter DisplayName="asdasd" Id="hdfh" IsPassword="false" IsRequired="true"></ConnectionParameter>
<ConnectionParameter DisplayName="asdad" Id="dfgdf" IsPassword="false" IsRequired="true"> </ConnectionParameter>
</ConnectionParameters>
</Test>
How can I loop through each "ConnectionParameter" tag inorder to get the attributes like Id,DisplayName etc using xdocument?
I tried like this,
XDocument xdoc = new XDocument();
xdoc= XDocument.Parse(fileContent);
var saveResult = from b in xdoc.Descendants("ConnectionParameters")
select new
{
success = (string)b.Element("ConnectionParameter").Attribute("Id").Value ?? string.Empty,
};
But it only returns the first node only
You're currently looping through all the ConnectionParameters elements (of which there's only one) and selecting the first ConnectionParameter element (using the Element call). You want to just loop through the ConnectionParameter elements:
// Note the lack of creating a new XDocument for no reason
XDocument xdoc = XDocument.Parse(fileContent);
var saveResult = from b in xdoc.Descendants("ConnectionParameter")
select new
{
success = (string) b.Attribute("Id") ?? ""
};
Or to avoid creating an anonymous type for no obvious reason, and using plain "dot notation" as the query expression isn't helping you much:
XDocument xdoc = XDocument.Parse(fileContent);
var saveResult = xdoc.Descendants("ConnectionParameter")
.Select(b => (string) b.Attribute("Id") ?? "");
If you prefer to make the parent element names explicit, you could use:
XDocument xdoc = XDocument.Parse(fileContent);
var saveResult = xdoc.Element("Test")
.Element("ConnectionParameters")
.Descendants("ConnectionParameter")
.Select(b => (string) b.Attribute("Id") ?? "");
Or:
XDocument xdoc = XDocument.Parse(fileContent);
var saveResult = xdoc.Root
.Element("ConnectionParameters")
.Descendants("ConnectionParameter")
.Select(b => (string) b.Attribute("Id") ?? "");
Load your xml into xDocument, then you can do something like this (can't remember exact syntax)
xDoc.Root.Descendants("ConnectionParameters").Attribute("DisplayName").Value;

Dictionary to XML

So, I have the following function that takes in a Dictionary of Users and ControlNumbers and outputs it to XML. Found some LINQ online that did this very well; but I have one small problem.
static Dictionary<string, User> UserClassDict = new Dictionary<string, User>();
static void DictionaryToXML(Dictionary<string,User> UserClassDict)
{
XElement el = new XElement("root", UserClassDict.Select(kv => new XElement(kv.Key, kv.Value.ControlNumber
)));
}
The XML looks like this:
<root>
<adolan>792365</adolan>
<afeazell>791964</afeazell>
<amsmith>790848</amsmith>
<asnyder>790948789358</asnyder>
</root>
But as you can see, the ControlNumbers are generally 6 digits long (HOWEVER this is not always the case). What I would like to happen is something similar to this.
<root>
<adolan>
<controlNumbers>123456</controlNumbers>
</adolan>
<asnyder>
<controlNumbers>222111</controlNumbers>
<controlNumbers>333222</controlNumbers>
</asnyder>
</root>
Eventually I will have the program read this XML file at start up and populate the Dictionary so this XML will eventually get pretty large. Any ideas would be helpful.
Try this
XElement el = new XElement("root",
UserClassDict.Select(kv => new XElement(kv.Key,
kv.Value.ControlNumbers.Select(num => new XElement("controlNumbers", num))))
);
I don't fully understand how 2 or more control numbers are represented in your dictionary, but if you want to do some more complex xlm generation, you can change your lambda so that it invokes a method.
kv => new XElement(kv.Key, kv.Value.ControlNumber)
would change to
kv => BuildXMLElement(kv)
and you can implement BuildXMLElement to build the element as you like
Change your el to
XElement el = new XElement("root", UserClassDict.
Select(kv => new XElement(kv.Key,
from it in kv.Value.ControlNumber
select new XElement("controlNumbers", it)
)));
The above LINQ query will create multiple controlNumbers tags
To concatenate, use
XElement el = new XElement("root", UserClassDict.
Select(kv => new XElement(kv.Key,
String.Join(",", kv.Value.ControlNumber.ToArray())
)));

Categories

Resources