My questions is regarding XML to LINQ where i have something as following structure:
<Or>
<value />
<Or>
<value />
<Or> //this is the deepest "or" element i should get in this case
<value />
<value />
</Or>
</Or>
</Or>
Which i basically build programmatically through the recrusion, but my questions i rather how to get the deepest Or element?
If i do:
elements.Element("Or"), it just gets me the first top element Or ....
Waitin for response.
XDocument xDoc = XDocument.Parse(xml); //XDocument.Parse(filename);
var deepestOr = xDoc.Descendants("Or")
.First(or => !or.Descendants("Or").Any());
Try that
var bench = XElement.Parse(#"<Or><value /><Or><value /><Or><value /><value /></Or></Or></Or>");
var lastOne = bench.Descendants("Or").Where( n => n.NodeType == XmlNodeType.Element).Last();
Result:
<Or>
<value />
<value />
</Or>
No matter how deep it is
This will give you the result:
XDocument doc = XDocument.Parse(#"<Or><value /><Or><value /><Or><value /><value /></Or></Or></Or>");
// take 'Or' node which contains no 'Of' nodes
var deepest = doc.Descendants("Or").Where(node => node.Descendants("Or").Count() == 0);
Related
I want to retrive some fields with CAML Query - everytime when i execute query for example:
query.ViewXml = string.Format(#"
<View>
<Query>
<Where>
<Eq>
<FieldRef Name='IDCardNumber' LookupId='TRUE'/>
<Value Type='Text'>12345</Value>
</Eq>
</Where>
</Query>
</View>
< ViewFields >
< FieldRef Name = 'Title' />
</ ViewFields >)");
var items = list.GetItems(query);
clientContext.Load(items);
clientContext.ExecuteQuery();
Query returns 0 elements.
I tried to get all elements and with CamlQuery.CreateAllItemsQuery(); - and in date I see correct count in list data, but FieldValues in elements look like this:
Screenshot from VS Locals
In CAML Query Builder Tool:
<Where>
<IsNotNull>
<FieldRef Name='Title' />
</IsNotNull>
</Where>
</Query>
Returns: Screenshot from CAML Query Builder
How to get these values correctly?
I think the value type should be "Lookup" then your using the id of the lookup field (i.e. the id of the field in the alternative list)
<Eq>
<FieldRef Name='IDCardNumber' LookupId='TRUE'/>
<Value Type='Lookup'>12345</Value>
</Eq>
ViewFields goes in View
query.ViewXml = #"<View>
<Query>
<Where>
<Eq>
<FieldRef Name='IDCardNumber' LookupId='TRUE'/>
<Value Type='Lookup'>12345</Value>
</Eq>
</Where>
</Query>
<ViewFields>
<FieldRef Name = 'Title'/>
<FieldRef Name = 'IDCardNumber'/>
</ViewFields>
</View>
";
I need to get a specific list of items from a sharepoint list.
This is my working code (good for 2 conditions under OR element):
XmlDocument xmlDoc = new System.Xml.XmlDocument();
XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
XmlNode ndQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
ndQueryOptions.InnerXml = "<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>" + "<DateInUtc>TRUE</DateInUtc>";
ndViewFields.InnerXml = #"<FieldRef Name=""Title"" />";
ndQuery.InnerXml = "<Where><Or><Eq><FieldRef Name='Title'/><Value Type='Text'>Title1</Value></Eq><Eq><FieldRef Name='Title'/><Value Type='Text'>Title2</Value></Eq></Or></Where>";
try
{
XmlNode ndListItems = ListsService.GetListItems(sharepointList, null, ndQuery, ndViewFields, null, ndQueryOptions, null);
MessageBox.Show(ndListItems.OuterXml);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
However, if the queried items under the OR element exceeds 2, let's say we have 3. It will fail and returns 500 Internal Server Error.
ndQuery.InnerXml = "<Where><Or><Eq><FieldRef Name='Title'/><Value Type='Text'>Title1</Value></Eq><Eq><FieldRef Name='Title'/><Value Type='Text'>Title2</Value></Eq><Eq><FieldRef Name='Title'/><Value Type='Text'>Title3</Value></Eq></Or></Where>";
I don't know where I went wrong cause if I break it down, I don't see any problem.
Any idea?
OR can only ever have exactly two child nodes. If you want to OR three conditions together you need to OR two of them, and then Or that node with your other condition.
<Where>
<Or>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">Title1</Value>
</Eq>
<Or>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">Title2</Value>
</Eq>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">Title3</Value>
</Eq>
</Or>
</Or>
</Where>
CAML query can contains at most two comparison statement inside or block.
So in your case CAML query should be like this.
<Where>
<Or>
<Or>
<Eq><condition></Eq>
<Eq><condition></Eq>
</Or>
<Eq><condition></Eq>
</Or>
</Where>
I have a string in which I need to extract all of the FieldRef names from the ViewField section of the string. They need to be input into an array. Been struggling with this for a while since im new to c#. Thanks.
<View>
<Query>
<OrderBy>
<FieldRef Name="ID" />
</OrderBy>
</Query>
<ViewFields>
<FieldRef Name="LinkTitle" />
<FieldRef Name="User" />
<FieldRef Name="Permissions" />
</ViewFields>
<RowLimit Paged="TRUE">30</RowLimit>
<JSLink>clienttemplates.js</JSLink>
<XslLink Default="TRUE">main.xsl</XslLink>
<Toolbar Type="Standard"/>
</View>
This returns only FieldRefs from ViewFields:
var doc = XDocument.Parse(xmlString);
var results = doc.Root.Element("ViewFields").Elements("FieldRef")
.Select(e => e.Attribute("Name").Value);
You can use XDocument to load the string as xml and then use Linq to get the values.
var doc = XDocument.Parse(str);
var res = doc
.Descendants("ViewFields")
.Descendants("FieldRef")
.Select(x => x.Attribute("Name").Value);
Load method is trying to load xml from a file and LoadXml from a string
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
string xpath = "View/Query/ViewFields";
var nodes = xmlDoc.SelectNodes(xpath);
foreach (XmlNode childrenNode in nodes)
{
var arr = childrenNode.SelectSingleNode("//FieldRef").Value;
}
I have this query which attempts to find this record (which I know exists) in the AllDocs table within a Sharepoint content database:
The record has these values
DirName: /MYSITE/MYLIST/A_FOLDER
LeafName: B_FOLDER
So the URL looks like: /MYSITE/MYLIST/A_FOLDER/B_FOLDER
Here's the method I'm trying to write:
public bool CheckFolderExist(string folderPath)
{
var pathArray = folderPath.Split('/');
string folderName = pathArray.Last(); //The 'LeafName' part...
var temp = pathArray.Take(pathArray.Length - 1);
string folderOnly = string.Join("/", temp); //The 'DirName' part...
CamlQuery cq = new CamlQuery();
string query = #"<View>
<ViewAttributes Scope='RecursiveAll' />
<Query>
<Where>
<And>
<Eq>
<FieldRef Name='FileLeafRef' />
<Value Type='Text'>{0}</Value>
</Eq>
<Eq>
<FieldRef Name='FileDirRef' />
<Value Type='Text'>{1}</Value>
</Eq>
</And>
</Where>
</Query>
</View>";
query = string.Format(query, folderName, folderOnly);
cq.ViewXml = query;
//_accountList is initiated somewhere else for the moment, and it doesn't seem to be the problem for now...
ListItemCollection colFolder = _accountList.GetItems(cq);
_ctx.Load(colFolder);
_ctx.ExecuteQuery();
if (colFolder.Count == 0)
return false;
else
return true;
}
My method always returns false. I can only think of me perhaps using the wrong field names in the CAML query.
Any ideas ?
Thanks.
I ended up correcting the CAML query for this:
string query = #"<View Scope='RecursiveAll'><Query><Where>
<And>
<Eq>
<FieldRef Name='FSObjType' />
<Value Type='Text'>1</Value>
</Eq>
<Eq>
<FieldRef Name='FileRef' />
<Value Type='Text'>{0}</Value>
</Eq>
</And>
</Where></Query></View>";
I have some code that I wrote to build up an XML recursively, and it works very good as intended except one thing, that is not so generic.
The array is
string[] countries= string[]{ ..... }
My idea to have is following, if an array contains only 1 string than it should be:
<Where>
<Eq>
<FieldRef />
<Value />
</Eq>
</Where>
If there are more then one, than it should contain <OR>, but for the last string value should be in the same OR: so basically it would be something like that for 4 items:
<Where>
<Or>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">Canada</Value>
</Eq>
<Or>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">New Zealand</Value>
</Eq>
<Or>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">United States</Value>
</Eq>
<Eq>
<FieldRef Name="Title" />
<Value Type="Text">Switzerland</Value>
</Eq>
</Or>
</Or>
</Or>
</Where>
Everything is nested.
Here is my code, it works great for the multi array but not for a single result:
private XElement Recursion(XElement parentElement, int counter)
{
if (counter == 0)
{
return parentElement;
}
XElement orElement = new XElement("Or");
XElement eqElement = new XElement("Eq");
XElement fieldElement = new XElement("FieldRef");
XAttribute nameAttribute = new XAttribute("Name", "Title");
fieldElement.Add(nameAttribute);
XElement valueElement = new XElement("Value", Countries[counter]);
XAttribute typeAttribute = new XAttribute("Type", "Text");
valueElement.Add(typeAttribute);
eqElement.Add(fieldElement);
eqElement.Add(valueElement);
orElement.Add(eqElement);
if (counter == 1)
{
eqElement = new XElement("Eq");
valueElement = new XElement("Value", Countries[0]);
valueElement.Add(typeAttribute);
eqElement.Add(fieldElement);
eqElement.Add(valueElement);
orElement.Add(eqElement);
}
XElement lastOrElement = parentElement.Descendants("Or").FirstOrDefault(or => !or.Descendants("Or").Any());
if (lastOrElement == null)
{
parentElement.Add(orElement);
}
else
{
lastOrElement.Add(orElement);
}
return Recursion(parentElement, --counter);
}
}
You need to test when counter is 1 if this if the first time into the function.
Probably the simplest is to alter your if (counter==1) block to test if the passed parent element was empty (or did not contain any other <OR> elements (it not clear how first you call this function and when the <where> element is added.
Try something like:
if (counter == 1)
{
if (!parentElement.Descendant("Or").Any())
{
//Single array case
return eqElement;
}
// Not single array case, code as before....
eqElement = new XElement("Eq");
...