Search for attribute value in xaml file using linq in C#? - c#

I know basic about getting node values from a xml file, but in a complicated xaml file I don't know how to write my linq query.
This is a sample of xaml I'm using:
<Activity something:something = " 2010" x:class = "example"..........>
<x:Members>
<x:Property Name= "aaaaa" Type = "Inargument" />
</x:Members>
<sap:abcdef>1322,2222</sap:abcdef>
<prwab:work sap2010:Annotation.AnnotationText = " I need this value" Active = "False" CreatedOn = "2014-07-09" ID = "123456" DisplayName = "theNameIneed">
<prwab:work.activity>
<prwais:collectingActivity sap2010:Annotation.AnnotationText = "I also need this value" > CreatedOn = "2014-07-09" ID = "1234232" DisplayName = "Ineed2">
<prwais .....>
</prwais>
</prwis:collectingActivity>
</prwab:work.activity>
</prwab:work>
</Activity>
I need to get the data in the lines that contain attribute "sap2010:Annotation.AnnotationText", and the value is going to be the content of sap2010:Annotation.AnnotationText, and key is going to be the attribute "ID" and attribute "displayName" in that line.
Here is the query I have right now, I know it's wrong but I don't know the proper way to write it:
var dataNodes = XElement.Load(file, LoadOptions.None);
Console.WriteLine("Loaded xaml file: " + file);
var dataNodesDictionary = from dataRecord in (dataNodes.Elements("prwab") && dataNodes.Elements("prwais"))//this line is wrong, but I dont know how to write it, since annotation may appears in different elements, and even if I only use "prwab" for testing, i still get nothing
where dataRecord.Attributes("Annotation.AnnotationText") != null
select new DictionaryEntry
{
Key = dataRecord.Attribute("DisplayName").Value.ToString() + "|" + dataRecord.Attribute("ID").Value.ToString(),
Value = dataRecord.Attribute("Annotation.AnnotationText").Value.ToString(),
};
Can some one help me please, thanks.

First find all elements that have the attribute. Then pull the attribute values.
// Name of the attributes we are looking
string ns = "http://schemas.microsoft.com/netfx/2010/xaml/activities/presentation";
XName name = XName.Get("Annotation.AnnotationText", ns);
XDocument doc = XDocument.Load("XMLFile1.xml");
var q = doc.Descendants().Where(e => e.Attribute(name) != null)
.Select(e => new DictionaryEntry { Key = e.Attribute("ID").Value, Value = e.Attribute(name).Value });
SIDE NOTE: In the future please paste in valid XML so it is easier for others to reproduce the issue.

Since this is XAML, you'll have a problem:
The attribute you're looking for can be written using a tag:
<prwab:work sap2010:Annotation.AnnotationText="I need this value">
...
</prwab:work>
This is equivalent to:
<prwab:work>
<sap2010:Annotation.AnnotationText>
I need this value
</sap2010:Annotation.AnnotationText>
...
</prwab:work>
So if you need a reliable way to read that, you should use the XamlReader class (the one from the System.Xaml namespace - not the one from System.Windows.Markup). It works in a similar way to XmlReader, but normalizes the XAML it presents to you.
It won't be as straightforward as a linq query, but will be more reliable.

Related

How to parse attributes in a collection using newtonsoft

Please see the XML below. Comparable_Sale is a repeating item. I am using new NewtonSoft’s Json parser and I need to be able to get the value of _Description attribute where the _type attribute equals a particular string value such as “GrossBuildingArea” from the element.
I have used the code below to parse property values with newtsonsoft, but I can’t figure out how to get at the attributes.
<COMPARABLE_SALE PropertySequenceIdentifier="3" ProjectName="Villages of Devinshire" ProjectPhaseIdentifier="1" PropertySalesAmount="132500" SalesPricePerGrossLivingAreaAmount="109.32" DataSourceDescription="FMLS, 5559496;DOM 80" DataSourceVerificationDescription="Tax Recs/2ndGen/Deeds" SalesPriceTotalAdjustmentPositiveIndicator="N" SalePriceTotalAdjustmentAmount="-1500" SalesPriceTotalAdjustmentGrossPercent="1.1" SalePriceTotalAdjustmentNetPercent="1.1" AdjustedSalesPriceAmount="131000">
<SALE_PRICE_ADJUSTMENT _Type="GrossBuildingArea"_Description="1,254"/>
<SALE_PRICE_ADJUSTMENT _Type="BasementArea" _Description="1,254 Sq.Ft."/>
<SALE_PRICE_ADJUSTMENT _Type="BasementFinish" _Description="1rr2ba4o"/>
</COMPARABLE_SALE>
This code gets me to the properties, but I can't see how to get at the attributes.
for each item in jobject.Children(Of JObject)()
For Each [property] In item.Children(Of JProperty)()
If [property].Value.Type = JTokenType.[String] Then
Dim newItem = New xmlRootValues()
newItem.Name = [property].Name
newItem.Value = [property].Value.ToString()
lstValues.Add(newItem)
End If
Next
next
Any help in either (C# or VB.net) would be much appreciated.
Thanks,
Chaos
To work with xml use an xml api like XDocument. Here you have an example in C#:
var xml = #"<COMPARABLE_SALE PropertySequenceIdentifier=""3"" ProjectName=""Villages of Devinshire"" ProjectPhaseIdentifier=""1"" PropertySalesAmount=""132500"" SalesPricePerGrossLivingAreaAmount=""109.32"" DataSourceDescription=""FMLS, 5559496;DOM 80"" DataSourceVerificationDescription=""Tax Recs/2ndGen/Deeds"" SalesPriceTotalAdjustmentPositiveIndicator=""N"" SalePriceTotalAdjustmentAmount=""-1500"" SalesPriceTotalAdjustmentGrossPercent=""1.1"" SalePriceTotalAdjustmentNetPercent=""1.1"" AdjustedSalesPriceAmount=""131000"">
<SALE_PRICE_ADJUSTMENT _Type=""GrossBuildingArea"" _Description=""1,254""/>
<SALE_PRICE_ADJUSTMENT _Type=""BasementArea"" _Description=""1,254 Sq.Ft.""/>
<SALE_PRICE_ADJUSTMENT _Type=""BasementFinish"" _Description=""1rr2ba4o""/>
</COMPARABLE_SALE>";
var xDoc = XDocument.Parse(xml);
var description = xDoc.Root.Elements("SALE_PRICE_ADJUSTMENT")
.First(e => e.Attribute("_Type").Value == "GrossBuildingArea")
.Attribute("_Description")
.Value;
In linq to xml you can also use Descendants and foreach to get all values for same element.
var obj = from item in xDoc.Descendants("SALE_PRICE_ADJUSTMENT")
select new
{
_Descr = item.Attribute("_Description").Value,
_Type = item.Attribute("_Type").Value
};

Read particular XML

I have this XML:
<palinsesto>
<giorno label="Mer" data="2014/12/31">
<canale description="Premium Cinema" id="KE">
<prg Pod="N" Nettv="N" orafine="06:30" orainizio="06:00" replica="No" primaTv="No">
<durata duratapixel="30">30</durata>
<tipologia>Type</tipologia>
<titolo>evento iniziato ieri</titolo>
<descrizione>--</descrizione>
<audio sottotitoli="No subtitles" audioType="Mono" doppioAudio="One language">Not used</audio>
<parentalRating>LIBERO DA DIVIETI</parentalRating>
<trafficLight/>
<anno>--</anno>
<paese>--</paese>
and i need to read the value in prg class and palinsesto class, i try in this mode but not work
XDocument doc = XDocument.Parse(e.Result);
var canal = doc.Descendants(XName.Get("description", "canale")).FirstOrDefault();
var date = doc.Descendants(XName.Get("data", "giorno")).FirstOrDefault();
var title = doc.Descendants(XName.Get("titolo", "prg")).FirstOrDefault();
return always error
It looks like you've misunderstood names, attributes and elements. It looks like you just want something like:
XDocument doc = XDocument.Parse(e.Result);
var root = doc.Root;
var canal = root.Element("canale").Attribute("description").Value;
var date = root.Element("giorno").Attribute("data").Value;
var title = root.Element("titolo").Value;
However:
Currently none of your first three elements are closed, which would cause the above to fail; it's not clear what your real XML would look like. You should indent it to show the intended structure.
Your date is not represented in the normal way for XML - if you're in control of the XML, it would be better to have a value of 2014-12-31
The above code assumes you just want the first element from the root. If that's not the case, you'll need to give us more information
You do not require this XName overload here - the second parameter is used to provide a namespace, which isn't present in the xml you've provided. I believe you are confusing attributes and xmlns namespaces. In order to obtain the attributes, use .Attributes(), as follows:
var canal = doc.Descendants("canale").Attributes("description").FirstOrDefault();
var date = doc.Descendants("giorno").Attributes("data").FirstOrDefault();
var title = doc.Descendants("prg").Attributes("titolo").FirstOrDefault();

Linq to XML dynamic XML Decendants

I'm parsing a lot of XML files using Linq to XML synatx, everything works when I try to access top level elements
var indexroot = (from element in prodcutDocument.Root.Descendants("indexroot")
select new
{
model = (string)element.Element("MODEL"),
}).FirstOrDefault()
The problem occurs when I need to access lower level childs of that document I tried:
var indexroot = (from element in prodcutDocument.Root.Descendants("indexroot")
select new
{
ddName = (string)element.Descendants("DD_NAME").Elements("name").First();
}).FirstOrDefault()
and
var indexroot = (from element in prodcutDocument.Root.Descendants("indexroot").Descendants("DD_NAME")
select new
{
ddName = (string)element.Element("name")
}).FirstOrDefault();
Sadly none of that works and i get same error "Sequence contains no elements". And one more thing sometimes the XML document contains those tags and sometimes not is something like this enough for handling this case?
var indexroot = (from element in prodcutDocument.Root.Descendants("indexroot").Descendants("DD_NAME")
select new
{
ddName = (string)element.Element("name") ?? "-"
}).FirstOrDefault();
Edit:
I don't think is possible to paste short version of XML that would be simple, so here's full version: http://pastebin.com/uDkP3rnR and for the code example:
XDocument prodcutDocument = XDocument.Load(this.ServerPATHData + file);
var indexroot = (from element in prodcutDocument.Root.Descendants("indexroot")
select new
{
modelis = (string)element.Element("MODELIS"),
T2918_0 = (string)element.Descendants("dd_DARBINIS_GRAFIKAS_SPEC").First()
}).FirstOrDefault();
writeTxt.WriteLine("modelis: " + indexroot.modelis);
writeTxt.WriteLine("T2979_0" + indexroot.T2918_0);
In examining the sample XML that you posted on PasteBin, it appears to me that the elements that you mention appear only once. To access them, you can simply specify a path to each as follows:
XElement indexroot = document.Root.Element("indexroot");
XElement modelis = indexroot.Element("MODELIS");
XElement dd_dgs = indexroot.Element("dd_DARBINIS_GRAFIKAS_SPEC");
XElement voltageuv = dd_dgs.Element("VoltageUV");
string t2979_0 = (string)voltageuv.Element("T2979_0");
string t2861_60 = (string)voltageuv.Element("T2861_60");
string t2757_121 = (string)voltageuv.Element("T2757_121");
(Note that you may need to check for null if there is a chance that any of the elements you are trying to access may not be present. Without doing so, you'll encounter a NullReferenceException.)
Here is a snippet of the XML that you posted to give context to the above code:
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<PDB>
<indexroot>
<ed_BENDRA_MAKS_SUV_GALIA>1.45</ed_BENDRA_MAKS_SUV_GALIA>
<ed_BENDRA_MAKS_SROVE>6.48</ed_BENDRA_MAKS_SROVE>
<TIPAS>1</TIPAS>
<MODELIS>RIS 2500 HW EC 3.0</MODELIS>
<dd_DARBINIS_GRAFIKAS_SPEC>
<VoltageUV>
<T2979_0>229,42</T2979_0>
<T2861_60>227,98</T2861_60>
<T2757_121>228,97</T2757_121>
</VoltageUV>
<CurrentIA>
<T2979_0>2,56</T2979_0>
<T2861_60>2,63</T2861_60>
<T2757_121>2,72</T2757_121>
</CurrentIA>
</dd_DARBINIS_GRAFIKAS_SPEC>
</indexroot>
</PDB>
You can just change:
element.Descendants("dd_DARBINIS_GRAFIKAS_SPEC").First()
to this:
element.Descendants("dd_DARBINIS_GRAFIKAS_SPEC").FirstOrDefault() ?? "-"

LINQ TO XML attribute tag give no object reference error

Hi i am doing as follow
XDocument xmlDoc = XDocument.Load(#"F:\test2.xml");
var q = from c in xmlDoc.Descendants("autoivr.ok")
where c.Element("LS_CZIP4").Value == "1234"
select new
{
name = c.Element("LS_LIN").Value,
state = c.Element("LS_STATE").Value
};
When i use
where c.attribute("LS_CZIP4").Value == "1234"
i get error of object reference not set but when i use c.element there is no such error.
Following is the xml i made which is actually a table in sql converted to xml file
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<autoivr.ok>
<LS_LIN>abc</LS_LIN>
<LS_STATE>def</LS_STATE>
<LS_TYPE>5</LS_TYPE>
<LS_CZIP4>1234</LS_CZIP4>
<priority>0</priority>
</autoivr.ok>
Can someone let me know the problem and how can i resolve and can i work with element tag only instead of attribute . Thank You
Use casting instead of accessing Value property. Casting to string will return null for non-existing elements. Getting Value will throw an exception
XDocument xmlDoc = XDocument.Load(#"F:\test2.xml");
var q = from c in xmlDoc.Descendants("autoivr.ok")
where (string)c.Element("LS_CZIP4") == "1234"
select new
{
name = (string)c.Element("LS_LIN"),
state = (string)c.Element("LS_STATE")
};
BTW you need closing tag for <DocumentElement>. Also LS_CZIP4 is element, not attribute. See the difference here XML Elements vs. Attributes.
Element: <LS_LIN>abc</LS_LIN>
Attribute: <autoivr.ok LS_LIN="abc">

Using LINQ to XML to Process XML in Multiple Namespaces

I'm trying to parse results from the YouTube API. I'm getting the results correctly as a string, but am unable to parse it correctly.
I followed suggestions on a previous thread, but am not getting any results.
My sample code is:
string response = youtubeService.GetSearchResults(search.Term, "published", 1, 50);
XDocument xDoc = XDocument.Parse(response, LoadOptions.SetLineInfo);
var list = xDoc.Descendants("entry").ToList();
var entries = from entry in xDoc.Descendants("entry")
select new
{
Id = entry.Element("id").Value,
Categories = entry.Elements("category").Select(c => c.Value)
//Published = entry.Element("published").Value,
//Title = entry.Element("title").Value,
//AuthorName = entry.Element("author").Element("name").Value,
//Thumnail = entry.Element("media:group").Elements("media:thumnail").ToList().ElementAt(0)
};
foreach (var entry in entries)
{
// entry.Id and entry.Categories available here
}
The problem is that entries has a count of 0 even though the XDocument clearly has the valid values.
The value of the response variable (Sample XML) can be seen here: http://snipt.org/lWm
(FYI: The youTube schema is listed here: http://code.google.com/apis/youtube/2.0/developers_guide_protocol_understanding_video_feeds.html)
Can anyone tell me what I'm doing wrong here?
All the data is in the "http://www.w3.org/2005/Atom" namespace; you need to use this throughout:
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
...
from entry in xDoc.Descendants(ns + "entry")
select new
{
Id = entry.Element(ns + "id").Value,
Categories = entry.Elements(ns + "category").Select(c => c.Value)
...
};
etc (untested)
When you see prefix:name, it means that name is in the namespace whose prefix has been declared as prefix. If you look at the top of the document, you'll see an xmlns:media=something. The something is the namespace used for anything with the prefix media.
This means you need to create an XNamespace for each of the namespaces you need to reference:
XNamespace media = XNamespace.Get("http://search.yahoo.com/mrss/");
and then use media for the names in that namespace:
media + "group"
The namespaces in this document are:
xmlns="http://www.w3.org/2005/Atom"
xmlns:app="http://www.w3.org/2007/app"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
xmlns:gd="http://schemas.google.com/g/2005"
xmlns:gml="http://www.opengis.net/gml"
xmlns:yt="http://gdata.youtube.com/schemas/2007"
xmlns:georss="http://www.georss.org/georss"
You need to set the namespace.
Creating an XName in a Namespace
As with XML, an XName can be in a namespace, or it can be in no namespace.
For C#, the recommended approach for creating an XName in a namespace is to declare the XNamespace object, then use the override of the addition operator.
http://msdn.microsoft.com/en-us/library/system.xml.linq.xname.aspx

Categories