Searching String to Xml file in C# - c#

<AccessUrl>
<Url>/User/Index</Url>
<Url>/EmailAccounts/Index</Url>
<Url>/Registration/Index</Url>
</AccessUrl>
I have a xml file. I wand to search a string in it. I have written a C# code for it.
string Url="/User/Index";// or One of the above value from file.
var CheckPermission = (from a in doc.Elements("AccessUrl")
where a.Element("Url").Value.Contains(Url)
select a).Any();
but it only works OK with first Url value from file. But if i change the string Url="/EmailAccounts/Index";. It doesn't show any match even the url value exists in xml file.Well i tried a lot but didn't get succeed yet.

This is because a.Element("Url") gives you the first child element with specified name. You should go through all children instead with something like:
a.Elements("Url").Any(u => u.Value.Contains(Url))

This is because you are calling:
where a.Element("Url")
This will return the first matching element.
From the docs:
Gets the first (in document order) child element with the specified System.Xml.Linq.XName
You need to use something like this to check all elements:
var CheckPermission = (from a in doc.Descendants("Url")
where a.Value.Contains(Url)
select a).Any();

This appears to work.
string url="/EmailAccounts/Index";// or One of the above value from file.
var checkPermission = xml.Elements("AccessUrl").Elements("Url").Any(x => x.Value == url);

Related

Using C # LINQ to Select within 2 tags that has a descendant node equal to a certain value?

I'm trying to select all objects within 2 tags specifically <AR>'s that contains an element that's a descendant of <AR>: <RL> with a certain value say 2. <RL> can be buried an arbitrary number of levels within <AR>'s, but will always be within <AR>. How can I do this in LINQ?
EX1:
<ARS>
<AR>
<EI> </EI>
<RL>5</RL>
</AR>
<AR>
<EI> </EI>
<RL>2</RL>
</AR>
</ARS>
Result :
<AR>
<EI> </EI>
<RL>2</RL>
</AR>
I tried using
IEnumerable<XNode> test_var = from result in doc.Descendants("AR")
where result.DescendantNodes()
But go from here, but this threw an error msg
var test_var = from result in doc.Descendants("AR")
where result.Descendants("RL").Any(x => (int)x == 2)
select result;
First problem is you need a select statement, such as adding select result.
Additionally your where needs to be a boolean. It sounds like you are looking for existence, which is frequently handled via the Any() extension method.
var searchString = "2";
IEnumerable<XElement> test_var = from result in doc.Descendants("AR")
where result.Descendants("RL").Any(xelm => xelm.Value == searchString)
select result;

Linq to XML: Queries for If blocks C#

I've got XML set up like this
<customers>
<customer id="1">
<name title="Mr" first="John" last="Smith" />
<contact number="07123123123" email="john.smith#johnsmith.com" />
<address postcode="E1 1EW">1 Paper Street, London, England, GB</address>
</customer>
(...)
</customers>
I'm trying to query it with Linq to XML for learning purposes. So far I can XDocument.Load the file fine and add/remove etc. But I can't seem to figure out a way to query my XML documents for use in an if block. for example something like (Pseudo code):
XDocument document = XDocument.Load("People.xml");
if(
exists(
document.customers.customer.name.first.value("john")
&& document.customers.customer.name.last.value("smith")
)
)
{
bool exists = true;
}
Whatever I try something the compiler will either laugh at me or spit out something about how it cannot implicitly convert an Ienumerable bool to a bool.
I've been trying many combinations of things from many different google searches for a while now and I think guessing is starting to do more harm than good, can anybody provide a C# snippet that would work in an if block for my xml setup? Just to see if first and last name exist together in the same node. Usually once I see something actually work I can take it from there. Most of the questions I find on the net are only searching to see if the entire node exists or are only searching for one attribute and I just can't seem to tailor it.
(Before anybody bursts into flames over my XML structure, this is not for production purposes, I just want to get a grasp of using this in case I need to in an upcoming project.)
Bonus love for anybody that can link any documentation that's not MSDN (I already have about 10 tabs open on it) and involves some good low level/beginner tutorials on Linq to XML.
To check for John Smith exists as a customer in your XML you ll use
XDocument doc = XDocument.Load(Path);
var customers = doc.Descendants("customer");
//To Check for John Smith
if (customers.Elements("name")
.Any(E => E.Attribute("first").Value == "John"
&& E.Attribute("last").Value == "Smith"))
{
//Do your thing
}
Created a boolean called check to hold the result.
do a count on how many elements called name have attributes First=john and last=smith
Then set the result to check variable.
BTW your XML was missing a " in front of John. That will cause you problems :)
bool check;
var res = XDocument.Load(#"c:\temp\test.xml");
var results = res.Descendants("name")
.Where(x => x.Attribute("first").Value == "john" && x.Attribute("last").Value == "smith")
.Select(x => x.Elements()).Count();
check = results != 0;
XPath is your friend
using System.Xml.XPath;
...
void foo(){
XDocument document = XDocument.Load("People.xml");
var firstCustomerNode = document.XPathSelectElement(
"/customers/customer[0]/name"
);
var hasfirstNameAndLastName = firstCustomerNode.Attribute("firstname") != null && firstCustomerNode.Attribute("lastname") != null;
if(hasfirstNameAndLastName)
{
}
}
Please note that you may also use a schema to validate your Xml, but it's more complex to write.
If you don't want to use XPath, you may also write:
var firstCustomerNode = document.Root.Element("Customers").Elements("customer").First().Element("name");
But honestly, the XPath query is far more readable, and will simplify the error check. This code suppose all the elements up to the target node exists. If not, your code will fail with a poor NullReferenceException.
You need to start by querying the Document.Root.Descendants. Then a method such as IfExists
var nodes = document.Root.Descendants("customer");
bool IfExists(string FirstName, string LastName) {
return nodes.Elements("name").Any(node =>
node.Attribute("first").Value.Equals(FirstName) &&
node.Attribute("last").Value.Equals(LastName));
}
You may want to add exception handling in case an attribute is missing or contains an empty value.

LINQ to XML - Where clause

I have an XML file with 2 types of information - Locations and job types which is determined by the SLvl value. I wish to bind the SearchTxt value for these to 2 drop downs (one for locations, one for job types) to be used as filters on my page.
The problem is I cant quite get my where clause to filter on the SLvl value. With the where clause in no results are returned. If I remove it the query does return all the text values.
C#
using System.Xml.Linq;
using System.Linq;
.....
// Loading from file
XDocument loaded = XDocument.Load(#"http://[LINKREMOVED]/vacancies.aspx");
// Query the data
var q = (from c in loaded.Descendants("items")
where c.Element("SLvl").ToString() == "0"
select c.Element("SearchTxt").ToString()).Distinct();
// Populate drop down
foreach(string name in q)
{
ddlLocation.Items.Add(new ListItem(name, name));
}
XML:
<VacancyMatch>
<items>
<SearchID>60</SearchID>
<SearchTxt>Scotland</SearchTxt>
<ParentID>0</ParentID>
<SearchCatID>1</SearchCatID>
<SLvl>1</SLvl>
<SubCat>1</SubCat>
</items>
<items>
<SearchID>92</SearchID>
<SearchTxt>Accounting</SearchTxt>
<ParentID>60</ParentID>
<SearchCatID>2</SearchCatID>
<SLvl>2</SLvl>
<SubCat>2</SubCat>
</items>
... More items here
</VacancyMatch>
I guess the problem is that the data is at the same level? Its my first time using LINQ to XML so any help is greatly appriciated.
Note:
XML is provided by a third party so formatting is up to them.
Drop the .ToString() and use .Value property instead:
var values = loaded.Descendants("items")
.Where(i => i.Element("SLvl").Value == "0")
.Select(i => i.Element("SearchTxt").Value)
.Distinct();
Calling ToString() on XElement will return entire node as text. For example, if we change i.Element("SearchTxt").Value in the query above to i.Element("SearchTxt").ToString() it will produce strings such as:
<SearchTxt>Accounting</SearchTxt>
Accessing Value property will extract node's inner text - "Accounting" in this case.
This:
where c.Element("SLvl").ToString() == "0"
should be:
where c.Element("SLvl").Value == "0"
You can't get a value of an element with "ToString()" method, you need to read it's "Value" property instead.
Same goes for any other lines where you are trying to get a value of an element.
Hope it helps.
I notice one problem, you use ToString() on the XElements which is not exactly what you want, I think :), to get the text content of a XElement use the Value property.
http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.value.aspx

Linq to XML Remove multiple returns

Hi have a Linq Query to extract some information. Following is the part of it.
node = "DocumentClass";
AVariable="Something"
na="NA";
var documentClassesScript = (from documentClass in configparentXML.Descendants(node)
where documentClass.Attribute("Name").Value.Contains(AVariable)
select new ReadingXmlWithLinq
{
CustomStorageString = documentClass.Element("ValidationPluginAssociations") != null ? documentClass.Descendants("ValidationPluginAssociation").Attributes("CustomStorageString").Single().Value : na,
}
).Distinct();
In Some case i got following error
Sequence contains more than one
element
The reason is ValidationPluginAssociations contain more than one ValidationPluginAssociation. I need to distinct and get only one of them. Is there any way to get it.
if there is no need to have single object you can use First:
documentClass.Descendants("ValidationPluginAssociation")
.Attributes("CustomStorageString").First().Value

Get SharePoint List Visible Columns Names through Web Service using C#

I want to get all visible columns (Hidden == false) for specific list in sharePoint site, I tried to look through the SharePointWebService.Lists.GetList(listName), but couldn't find anything useful, also checked the methods provided by the Lists WebService and also nothing new,
Please advice.
You can use the GetListAndView method of the Lists web service to get the schemas for the list and a view.
From the documentation, if you leave the viewName parameter empty, the default view will be returned. Then, you can read the <ViewFields></ViewFields> node for the list of fields.
*Edit*
Turns out using XPath to query the returned XML was tougher than I thought... here is what I came up with:
XmlNode result = webService.GetListAndView("My Pictures", string.Empty);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(result.OwnerDocument.NameTable);
nsmgr.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/soap/");
string xpathQuery = "sp:View/sp:ViewFields/sp:FieldRef";
XmlNodeList nodes = result.SelectNodes(xpathQuery, nsmgr);
for (int i = 0; i < nodes.Count; i++)
{
Console.WriteLine(nodes[i].Attributes["Name"].Value);
}
Looks like you have to have a XmlNamespaceManager otherwise your query always returns no values. Something about specifying the namespace... Here is a good reference.
The GetList() method returns a CAML fragment that includes the list's field (column) definitions. You might want to try an XPath expression:
XmlNode list = yourListService.GetList("yourListName");
XmlNodeList visibleColumns
= list.SelectNodes("Fields/Field[not(#Hidden) or #Hidden='FALSE']");
I used the above code but, after a long search I found the solution to get all or custom columns from the sharepoint list. The code for that is shared on ..
Custom Columns or ALL Columns
Solution is quite simple. Using GetList() or similar functions is the wrong way to go.
Instead use GetListContentTypesAsync() to get Content ID and then get the specific ContentType using GetListContentTypeAsync(), it returns XML which includes all visible columns in sharepoint list:
var Contents = await soapListClient.GetListContentTypesAsync(list.Title, "0x01"); // 0x01 is kind of a root element for sharepoint.
String ContentID = Contents.Body.GetListContentTypesResult.Descendants().FirstOrDefault().Attribute("ID").Value.ToString();
var ContentType = await soapListClient.GetListContentTypeAsync(list.Title, ContentID);
XElement xmll = XElement.Parse(ContentType.Body.GetListContentTypeResult.ToString());

Categories

Resources