Repository navigation
Expand file tree
/
Copy pathuQuery-Nodes.cs
More file actions
343 lines (301 loc) · 9.81 KB
/
Copy pathuQuery-Nodes.cs
File metadata and controls
343 lines (301 loc) · 9.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.XPath;
using umbraco;
using umbraco.NodeFactory;
namespace uComponents.Core
{
/// <summary>
/// uQuery sub-class for Nodes
/// </summary>
public static partial class uQuery
{
/// <summary>
/// Gets the Root Node Id (-1)
/// </summary>
public static readonly int RootNodeId = -1;
/// <summary>
/// Get a collection of Umbraco Nodes from an XPath expression
/// </summary>
/// <param name="xpath">XPath expression to get Nodes, can use $ancestorOrSelf which will use the current Node if published, else it'll use the nearest published parent
/// $currentPage will be depreciated</param>
/// <returns>an empty collection or a collection of nodes</returns>
public static List<Node> GetNodesByXPath(string xpath)
{
var nodes = new List<Node>();
// resolve the XPath expression with any Umbraco-specific parameters
xpath = uQuery.ResolveXPath(xpath);
// Get Umbraco Xml
var xPathNavigator = content.Instance.XmlContent.CreateNavigator();
XPathExpression xPathExpression;
// Check to see if XPathExpression is in the cache
if (HttpContext.Current.Cache[xpath] == null)
{
// Build Compiled XPath expression
xPathExpression = xPathNavigator.Compile(xpath);
// Store in Cache
HttpContext.Current.Cache[xpath] = xPathExpression;
}
else // Get from Cache
{
xPathExpression = (XPathExpression)HttpContext.Current.Cache[xpath];
}
// [LK] Interested in exploring options to call custom extension methods in XPath expressions.
// http://msdn.microsoft.com/en-us/library/ms950806.aspx
// http://msdn.microsoft.com/en-us/library/dd567715.aspx
// Alternative is to render a Clean.xslt with the desired XPath, returning nodeIds
var xPathNodeIterator = xPathNavigator.Select(xPathExpression);
while (xPathNodeIterator.MoveNext())
{
var node = uQuery.GetNode(xPathNodeIterator.Current.GetAttribute("id", string.Empty));
if (node != null)
{
nodes.Add(node);
}
}
return nodes;
}
/// <summary>
/// The umbraco.content.Instance.XmlContent method from VB.NET causes an ambiguous issue,
/// so this method can gets the source xml directly from the DB
/// WARNING: xml is flat - every node in the content tree is a sibling
/// </summary>
/// <param name="xPath"></param>
/// <returns></returns>
public static List<Node> GetNodesByXPathViaSql(string xPath)
{
var nodes = new List<Node>();
var xmlDocument = uQuery.GetPublishedXml(UmbracoObjectType.Document);
var xPathNavigator = xmlDocument.CreateNavigator();
var xPathNodeIterator = xPathNavigator.Select(xPath);
while (xPathNodeIterator.MoveNext())
{
var node = uQuery.GetNode(xPathNodeIterator.Current.Evaluate("string(@id)").ToString());
if (node != null)
{
nodes.Add(node);
}
}
return nodes;
}
/// <summary>
/// Returns a collection of Nodes, from a delimited list of Ids (as per the format used with UltimatePicker)
/// </summary>
/// <param name="csv">string csv of Ids</param>
/// <returns>an empty collection or a collection or Nodes</returns>
public static List<Node> GetNodesByCsv(string csv)
{
var nodes = new List<Node>();
var ids = uQuery.GetCsvIds(csv);
if (ids != null)
{
foreach (string id in ids)
{
var node = uQuery.GetNode(id);
if (node != null)
{
nodes.Add(node);
}
}
}
return nodes;
}
/// <summary>
/// Builds a node collection from an XML snippet
/// </summary>
/// <param name="xml">
/// the expected Xml snippet is that stored by the Multi-Node Tree Picker (and XPathCheckBoxList when storing Ids)
/// "<MultiNodePicker>
/// <nodeId>1065</nodeId>
/// <nodeId>1068</nodeId>
/// <nodeId>1066</nodeId>
/// </MultiNodePicker>"
/// </param>
/// <returns>an empty list or a list of nodes</returns>
public static List<Node> GetNodesByXml(string xml)
{
var nodes = new List<Node>();
var ids = uQuery.GetXmlIds(xml);
if (ids != null)
{
foreach (int id in ids)
{
var node = uQuery.GetNode(id);
if (node != null)
{
nodes.Add(node);
}
}
}
return nodes;
}
/// <summary>
/// Get nodes by name
/// </summary>
/// <param name="name">name of node to look for</param>
/// <returns>list of nodes, or empty list</returns>
public static List<Node> GetNodesByName(string name)
{
return uQuery.GetNodesByXPath(string.Concat("descendant::*[@nodeName='", name, "']"));
}
/// <summary>
/// Get nodes by document type alias
/// </summary>
/// <param name="documentTypeAlias">The document type alias</param>
/// <returns>list of nodes, or empty list</returns>
public static List<Node> GetNodesByType(string documentTypeAlias)
{
if (uQuery.IsLegacyXmlSchema())
{
return uQuery.GetNodesByXPath(string.Concat("descendant::*[@nodeTypeAlias='", documentTypeAlias, "']"));
}
else
{
return uQuery.GetNodesByXPath(string.Concat("descendant::", documentTypeAlias, "[@isDoc]"));
}
}
/// <summary>
/// Get nodes by document type id
/// </summary>
/// <param name="documentTypeId">The document type id.</param>
/// <returns></returns>
public static List<Node> GetNodesByType(int documentTypeId)
{
return uQuery.GetNodesByXPath(string.Concat("descendant::*[@nodeType='", documentTypeId, "']"));
}
/// <summary>
/// Gets the node by URL.
/// </summary>
/// <param name="url">url to search for</param>
/// <returns>null or node matching supplied url</returns>
/// <remarks>Uses <c>uComponents.Core.XsltExtensions.Nodes.GetNodeIdByUrl</c></remarks>
public static Node GetNodeByUrl(string url)
{
return uQuery.GetNode(XsltExtensions.Nodes.GetNodeIdByUrl(url));
}
/// <summary>
/// Get top level content node
/// </summary>
/// <returns>the top level content node</returns>
public static Node GetRootNode()
{
return new Node(RootNodeId);
}
/// <summary>
/// checks to see if the current node can be got via the nodeFactory, if not then
/// checks to see if the current node can be got via an id on the QueryString
/// </summary>
/// <returns>the current node or null if not found</returns>
public static Node GetCurrentNode()
{
Node currentNode = null;
try
{
currentNode = Node.GetCurrent();
}
catch // if current node can't be found via the nodeFactory then Umbraco throws an exception
{
// look on QueryString for an id parameter (this is used in the backoffice)
currentNode = uQuery.GetNode(uQuery.GetIdFromQueryString());
}
return currentNode;
}
/// <summary>
/// Checks the supplied string can be cast to an integer, and returns the node with that Id
/// </summary>
/// <param name="nodeId">string representing the nodeId to return</param>
/// <returns>Node or null</returns>
public static Node GetNode(string nodeId)
{
int id;
Node node = null;
if (int.TryParse(nodeId, out id))
{
node = uQuery.GetNode(id);
}
return node;
}
/// <summary>
/// Wrapper for Node constructor
/// </summary>
/// <param name="id">id of Node to get</param>
/// <returns>Node or null</returns>
public static Node GetNode(int id)
{
Node node;
try
{
node = new Node(id);
if (node.Id == 0)
{
node = null;
}
}
catch
{
node = null;
}
return node;
}
/// <summary>
/// Resolves the XPath expression with any Umbraco-specific parameters.
/// </summary>
/// <param name="xpath">The xpath expression.</param>
/// <returns>Returns an XPath expression with the Umbraco-specific parameters resolved.</returns>
public static string ResolveXPath(string xpath)
{
if (!string.IsNullOrWhiteSpace(xpath))
{
var parameters = new[] { "$currentPage", "$ancestorOrSelf", "$parentPage" };
if (parameters.Any(xpath.Contains))
{
var ancestorOrSelfId = RootNodeId;
var parentPageId = RootNodeId;
var currentNode = uQuery.GetCurrentNode();
if (currentNode != null)
{
ancestorOrSelfId = currentNode.Id;
parentPageId = (currentNode.Parent != null) ? currentNode.Parent.Id : currentNode.Id;
}
else
{
// current node is unpublished or can't be found, so try via the Document API
var currentDocument = uQuery.GetCurrentDocument();
if (currentDocument != null)
{
// need to find first published parent
var publishedDocument = currentDocument.GetAncestorOrSelfDocuments().Where(document => document.Published == true).FirstOrDefault();
if (publishedDocument != null)
{
// found the nearest published document
ancestorOrSelfId = publishedDocument.Id;
parentPageId = (publishedDocument.Id == currentDocument.Id) ? currentDocument.ParentId : publishedDocument.Id;
}
}
}
// replace the parameters with corresponding XPath expression
xpath = xpath.Replace("$parentPage", string.Concat("/descendant::*[@id='", parentPageId, "']"));
xpath = xpath.Replace("$currentPage", "$ancestorOrSelf");
xpath = xpath.Replace("$ancestorOrSelf", string.Concat("/descendant::*[@id='", ancestorOrSelfId, "']"));
}
}
return xpath;
}
/// <summary>
/// Extension method on Node collection to return key value pairs of: node.Id / node.Name
/// </summary>
/// <param name="nodes">generic list of node objects</param>
/// <returns>a collection of nodeIDs and their names</returns>
public static Dictionary<int, string> ToNameIds(this List<Node> nodes)
{
var dictionary = new Dictionary<int, string>();
foreach (var node in nodes)
{
dictionary.Add(node.Id, node.Name);
}
return dictionary;
}
}
}