C#: Check particular attribute key-value pair is present using linq - c#

I want to check whether a particular attribute key-value pair is present using linq.
I am using following code to check:
bool keyPresent = xDocument.Element("noSqlDb").Element("elements").Elements("key")
.Where(el => el.Attribute("id").Equals(key.ToString()))
.Any();
My XML looks like below:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<noSqlDb>
<keytype>System.Int32</keytype>
<payloadtype>a</payloadtype>
<elements>
<key id="1">
<name>element</name>
<descr>test element</descr>
<timestamp>2015-10-02T23:54:07.6562371-04:00</timestamp>
<children>
<item>1</item>
<item>2</item>
<item>3</item>
</children>
<payload>
<item>CSE681</item>
<item>SMA</item>
<item>C#.net</item>
</payload>
</key>
</elements>
</noSqlDb>

You could simply use Xpath to try to find the element.
bool keyPresent = xDocument.XPathSelectElement(String.Format("//key[#id={0}]", key)) != null;
..or using LINQ
bool keyPresent = xDocument.Descendants()
.Any(e => e.Name == "key" && e.Attributes()
.Any(a => a.Name == "id" && a.Value == key.ToString()));

Related

Deserialize key/value xml into an object

Having some difficulties deserializing the following xml to an object in the most efficient/cleanest possible way:
<item xsi:type="ns2:Map" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item>
<key xsi:type="xsd:string">mailinglistid</key>
<value xsi:type="xsd:string">1</value>
</item>
<item>
<key xsi:type="xsd:string">uniqueid</key>
<value xsi:type="xsd:string">1a0d0d2195</value>
</item>
<item>
<key xsi:type="xsd:string">name</key>
<value xsi:type="xsd:string">OSM NL</value>
</item>
</item>
This is a single item along with its properties. As you can see the properties are defined as key/value pairs.
Because they are key value pairs i could not find a way to use the Xml deserialize attributes (as described in this question: How to deserialize xml to object )
Therefore i have created the following alternative:
// Retrieves all the elements from the "return" node in the Mailinglist_allResponse node.
var items = response.ResponseFromServer.Descendants(_engineResponseNamespace + "Mailinglist_allResponse").Descendants("return").Elements();
foreach (var item in items)
{
var values = item.Descendants("item").ToArray();
var list = new EngineMailingList
{
MailingListId =
values.Descendants("key")
.First(v => v.Value == "mailinglistid")
.ElementsAfterSelf("value")
.First()
.Value,
UniqueId =
values.Descendants("key")
.First(v => v.Value == "uniqueid")
.ElementsAfterSelf("value")
.First()
.Value,
Name =
values.Descendants("key")
.First(v => v.Value == "name")
.ElementsAfterSelf("value")
.First()
.Value,
};
result.Add(list);
As you can see this is alot more code than when using the deserialize attributes. Is there any way i could still use these attributes so that my code could be cleaner/ efficient? i am going to have to make alot of these functions otherwise.
I don't think attributes will work because of key/value structure. There is no way for a program to infer from the xml alone what properties an object has. I would make a static extension method helper function to get the values:
public static string GetValue(this XElement element, string key){
return values.Descendants("key")
.First(v => v.Value == key)
.ElementsAfterSelf("value")
.First()
.Value;
}
That way your code could look like this:
MailingListId = values.GetValue("mailinglistid"),
UniqueId = values.GetValue("uniqueid"),
Name = values.GetValue("name")

How I can filter my xml to a search value?

hi I want to translate my site for this I use a Xml file and with Linq to xml I want to get the value. here is my xml for example:
<?xml version="1.0" encoding="utf-8"?>
<Languages>
<values id="_hallo">
<value value="DE" display="Hallo"></value>
<value value="EN" display="Hello"></value>
<value value="CS" display="Tschechisch"></value>
<value value="ES" display="Spanisch"></value>
<value value="ZH" display="德國的"></value>
</values>
</Languages>
here is my c#:
private void SiteTranslate(string language)
{
string BrowserLanguage = Request.UserLanguages[0].ToString().Substring(0, 2).ToUpper(); // here I get "DE" or "EN" etc..
string btnadd_id = "_hallo"; // for example
XDocument x = XDocument.Load(Server.MapPath(#"~\App_Data\SiteLanguage.xml"));
string val = from tep in x.Descendants("values").Where(el => el.Attribute("id").Value == btnadd_id).
Descendants("value").
Where(l => l.Attribute("value").Value == language).Select //?????? :(
BtnAdd.Text = val;
}
It's a simple "get the one and only element" problem:
string val = x.Descendants("values")
.Where(el => el.Attribute("id").Value == btnadd_id)
.Elements("value")
.Where(l => l.Attribute("value").Value == language)
.SingleOrDefault()
.Attribute("display").Value;

Finding a specific xml element containt

Ihave a large xml file and I want to get child element value by giving the parent child element value, I am new in xml file please any help here is my xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<masterController> <uuid>XXXXXXXXXXXXXXXXXXXXXXXXX</uuid>
<channels>
<channel>
<nodeGroups>
<nodeGroup>
<analogNode>
<typeCode>8</typeCode>
<id>1</id>
<sdos>
<sdo>
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<datafield xmlns:xsi="http://www.XXXXX.XXXX/XXXXX/XMLSchema-instance"
xsi:type="intField">
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<offset>2</offset>
<size>1</size>
<readonly>true</readonly>
<isMappedToPdo>false</isMappedToPdo>
<ownerNodeSerial>12102904</ownerNodeSerial>
<ownerSdoIndex>3</ownerSdoIndex>
<data xsi:type="intData">
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">2</value>
<unit></unit>
<min>1</min>
<max>15</max>
</data>
<intValue>2</intValue>
</datafield>
<index>3</index>
<totalbytes>3</totalbytes>
</sdo>
<sdo>
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<datafield xmlns:xsi="http://www.XXXXX.XXXX/XXXXX/XMLSchema-instance"
xsi:type="intField">
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<offset>2</offset>
<size>1</size>
<readonly>true</readonly>
<isMappedToPdo>false</isMappedToPdo>
<ownerNodeSerial>12102905</ownerNodeSerial>
<ownerSdoIndex>4</ownerSdoIndex>
<data xsi:type="intData">
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">16</value>
<unit></unit>
<min>1</min>
<max>15</max>
</data>
<intValue>2</intValue>
</datafield>
<index>3</index>
<totalbytes>3</totalbytes>
</sdo>
</sdos>
</analogNode>
</nodeGroup>
</nodeGroups>
</channel> </channels> </masterController>
I' am trying this but am not geting anything:
XElement root = XElement.Load(Server.MapPath("sample.xml"));
IEnumerable<XElement> masterco = from el in root.Elements("sdo") where (from add in el.Elements("datafield")
where
(string)add.Element("ownerNodeSerial") == TextBox1.Text &&
(string)add.Element("ownerSdoIndex") == TextBox1.Text
select add)
.Any()
select el;
foreach (XElement el in masterco)
{
TextBox3.Text = (string)el.Element("value");
}
I want to get this:
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">16</value>
and be able to update it.
There is one major error in your query:
You are using Elements on root, but you are looking for the tag sdo which is not a direct child of the root tag. You have to use Descendants instead.
Additionally, I think you want to have an OR instead of an AND regarding the text of TextBox1.
Fix it:
var masterco = from el in root.Descendants("sdo")
where (from add in el.Elements("datafield")
where
(string)add.Element("ownerNodeSerial") == TextBox1.Text ||
(string)add.Element("ownerSdoIndex") == TextBox1.Text
select add).Any()
select el;
To actually get the value you want, you should use a different query. There is really no need to select the sdo tag at all.
var value = root.Descendants("datafield")
.Where(x => (string)x.Element("ownerNodeSerial") == TextBox1.Text ||
(string)x.Element("ownerSdoIndex") == TextBox1.Text)
.Select(x => (string)x.Element("data").Element("value"))
.Single();
TextBox3.Text = value;
You can see that I am assuming that in the whole XML document only one matching datafield/data/value entry exists. I derive that information from the way you update your textbox. This would make no sense if there would be multiple tags - the values would overwrite each other in the text box.

How to use SetElementValue on XDocument

This is the sample of my xml
<?xml version="1.0"?>
<SearchHistory>
<Search>
<title>Text 1</title>
<count>0</count>
</Search>
<Search>
<title>Text 2</title>
<count>0</count>
</Search>
</SearchHistory>
And I want to change the value of count of Text 1
this is what i tried:
xdoc.Descendants("Search")
.Where(x => x.Element("title").Value == tbSearch.Text)
.Single().SetElementValue("count", curCount);
You have to Save the XDocument when you have made changes
xDoc.Save(fileName);
xdoc.Descendants("Search")
.Where(x => x.Element("title").Value == tbSearch.Text)
.Single()
.Descendants("count")
.Single()
.Value = "1";

Delete xElement by xAttribute value

I have the following xml document:
<?xml version="1.0" encoding="utf-8"?>
<Categories>
<title>
<Type name="James">
<Field name="ref" value="79" />
<Field name="titleref" value="55" />
</Type>
</title>
</Categories>
I want to delete all of 'title' if the textBox1 text matches
I have the following, I know it doesn't work, but I wanted to see if you can see my logic.
xmldoc.Root.Elements().Where(x => x.Element("Type")).Where (x => x.Attribute("name").Value.Equals(textBox1.Text)).Select(x => x).Single().Remove();
Any help would be great
Thanks
You can use XPath (System.Xml.XPath)
xmldoc.XPathSelectElements(String.Format("//Type[#name='{0}']", textBox1.Text))
.Remove();
xmldoc.Root.Descendants( "Type" )
.Where( x => x.Attribute( "name" ).Value == textBox1.Text )
.Remove();

Categories

Resources