Parsing XML stream using LINQ - c#

I found a lot of examples and questions on this topic but what ever I try the result is blank.
From the xml I need to get out the first 'listing' element from there I need just the DisplayName and Address info.
var listings = from c in xdoc.Elements("listing") select c;

You are missing the namespace in your query. The name of the node is not listing it is namespace + listing
So you need to get the namespace of the wp element or use the local name property:
var listings = from c in xdoc.Descendants()
where c.Name.LocalName == "listing"
select c;
or you need to get the namespace and add it to the query
XNamespace ns = // namespace name here
var listings = from c in xdoc.Descendants(ns + "listing") select c;
listing will be defined as some variation of IEnumerable<XElement>. The exact type will vary depending on which query you used, but the important part is it will derive from IEnumerable<>.
The other problem is your use of the Elements() method. Elements() will only search the children of node defined by xdoc. Descendants() will also look in the child of the children and all other child nodes.
UPDATE 1 - Added more details on getting specific nodes from XML
Getting the address and displayname is basically the same process, in fact you can just add it to the original query or use a different query (it all depends on how you want to use it later - will you ever need the other elements of wp:listing or just the displayname and address?
If you might need others, then it seems logical to do it as a different query so you can query your result later. Readability also comes into play as nesting multiple queries inside of each other can make it difficult to read in my opinion.
Getting Address is the hardest part. You need to decide how you want it... do you want a XElement with all of the address parts as child nodes? Or do you want to construct a new object? Or do you just need a concatenated string?
But the general query would be something like this:
var result = from listing in listings
select new
{
Name = listing.Element(ns + "displayname").Value,
Address = listing.Element(ns + "address")
};
This would give you an IEnumerable<'a'> with a defined as an anonymous type consisting of a Name property (as a String) and an Address property (as an XElement). If you want something else, you have to replace Address = listing.Element(ns + "address") with appropriate line(s) of code.
If you just need another anonymous type, then you need to put a nested query in that line:
Address = from part in listing.Elements(ns + "address")
select new
{
FullStreet = part.Element(ns + "fullstreet").Value,
HouseNumber = part.Element(ns + "house").Value,
Street = part.Element(ns + "street").Value,
StreetType = part.Element(ns + "streettype").Value,
// continue for all Elements you need/want
};
Or you could just create an Address class and call the constructor or a factory method in the query and pass the XElement or the address parts.

Try to use Descendants instead of Elements
var listings = from c in xdoc.Descendants("listing") select c;

Related

C# Find XElement Descendant based on multiple attributes

I have to add information to an existing XML file. The data is going to be underneath an existing node. This has to do with Patient data, and I have to find the existing patient within the XML, so I can add the subsequent data to it. This data is encapsulated within a "PATIENTDETAILS" element.
While I found many articles on how to find a descendant via a single attribute, I need to use multiple attributes can try as I might, I can't seem to find how to use multiple attributes.
This is my current query (C#):
XElement patient = xmlDoc.Descendants(ns + "_PATIENTDETAILS").ToList().WHERE
(x => (string)x.Element(ns + "_PatientName") == currentPatientName).FirstOrDefault();
I need to add "_PatientAccNo", "_HicNo" and "_MedRecNo" to the where clause to ensure I find the right _PATIENTDETAILS before adding a new element beneath that patient with the new data.
I'm adding the new element after this query by doing:
XElement serviceLines = patient.Element("_PATIENTDETAILS");
xmlDoc.Element("_OCROUTPUT).Element("_PATIENTDETAILS").Add(new XELEMENT("_SERVICELINES",
new XElement(name, data),
Blah blah blah
If someone can give me an example of using multiple where clauses in finding a Descendant, I'd appreciate it.
You can combine conditions with a logical and which is && in C#.
XElement patient = xmlDoc.Descendants(ns + "_PATIENTDETAILS")
.Where(x => (string)x.Element(ns + "_PatientName") == currentPatientName &&
(string)x.Element(ns + "another element") == anotherValue &&
(string)x.Element(ns + "yet another element") == yetAnotherValue)
.FirstOrDefault();
See also: Conditional logical AND operator &&.
And also the .ToList() in there can be dropped. It adds no value.

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;

Dapper Multiple Results From single query

Hi i am trying to get to grips with Dapper.
My situation is i want to pull two values from a query into two separate strings. Im not sure if i am going about this in the correct way, but this is what i am doing:
string sql = #"Select type, name
FROM ZipData
WHERE Zip = #zip";
using (var multi = conn.QueryMultiple(sql, new { zip = zip }))
{
string result = multi.Read<string>().SingleOrDefault();
}
And i am getting Cannot access a disposed object. Object name: 'GridReader'. when trying to read the second string.The thing is it gets the first value correctly and has both the fields in in the reader i am trying to get. Im sure im misusing the api.
What am i doing wrong here? Ive googled but can find a specific example.
You are mis-using QueryMultiple. That is defined for compound SQL statements that return multiple result sets. Something like:
SELECT Foo FROM MyTable;
SELECT Bar FROM MyOtherTable;
On the other hand, you are trying to get two different columns from a single result set, so you should just use the normal Query method:
var result = conn.Query(sql, new { zip = zip }).Single();
var type = result.type;
var name = result.name;
Query returns an enumerable (because generally a query can return multiple rows). It appears that you only want one row, however, so we invoke .Single at the end to just get that row. From there, the return type is dynamic so you can simply refer to the properies implied by the columns in your SELECT statement: type and name.

Select EF entities that have all the given Tags (where tag is an EF entity)

I have the following situation:
An "Conversations" entity/table which has multiple Tags associated to it.
Tag is also an entity/table - the key/id is tagName (a string).
On the client side (javascript) I work with arrays of string when dealing with Tags.
Now I want want to retrieve all the conversations that have all given tags.
The input is an array of strings and the output should be a collection of Conversations
I've tried:
var filterTags = new List<EFModels.Tag>();
foreach (var tagName in tags)
{
filterTags.Add(new EFModels.Tag() { Name = tagName});
}
var conversations = from c in context.Conversations where !c.Tags.Except(filterTags).Any() select c ;
The problem with this is: Unable to create a constant value of type 'EFModels.Tag'. Only primitive types or enumeration types are supported in this context - which makes sense.
Now how can I do my select? What's the best approach? (I still want to use linq and not write the sql select)
You can project c.Tags to tag name.
I guess it will look like that
var conversations = from c in context.Conversations where !c.Tags.Select(tag => tag.Name ).Except(filterTags).Any() select c ;
Where filterTags is the list of strings containing the names of the tags

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