How do I check using a razor template in Umbraco to determine if the current page is a descendant of a specific node? I'll be using a case statement.
Not sure if those methods still work with the latest version of Umbraco, but with 4.7.1 and DynamicNode there use to be those methods:
#Model.AncestorOrSelf(string nodeTypeAlias)
#Model.AncestorOrSelf(int level)
#Model.AncestorOrSelf(Func<DynamicNode, bool> func)
and those Helper functions:
#Model.IsDescendant(DynamicNode[,valueIfTrue][,valueIfFalse])
#Model.IsDescendantOrSelf(DynamicNode[,valueIfTrue][,valueIfFalse])
If you're using uComponents / uQuery from http://ucomponents.codeplex.com/ you can do something like:
var isChildOf = uQuery.GetCurrentNode().GetAncestorNodes().Where(n => n.NodeTypeAlias == "MyHomePage").First() != null;
(Note: I haven't tried this code, but have similar in production)
A quick and dirty way of doing it would be to check the nodes Path property (I think #Model.Path should get it). This should contain either a comma separate string or an array of numbers (not sure which off the top of my head) of the path from the node back to the root of the site. You can check for your parent node in that property. Which would save on more expensive lookups of nodes using LINQ or uQuery.
Related
I need to retrieve the collections to which a given document belongs in Marklogic.
I know xdmp command does that. But I need to use it in cts query to retrieve the data and then filter records from it.
xdmp:document-get-collections("uri of document") can't be run inside cts-query to give appropriate data.
Any idea how can it be done using cts query?
Thanks
A few options come to mind:
Option One: Use cts:values()
cts:values(cts:collection-reference())
If you check out the documentation, you will see that you can also restrict this to certain fragments by passing a query as one of the parameters.
**Update: [11-10-2017]
The comment attached to this asked for a sample of restricting the results of cts:values() to a single document(for practical purposes, I will say fragment == document)
The documentation for cts:values explains this. It is the 4th parameter - a query to restrict the results. Get to know this pattern as it is part of many features of MarkLogic. It is your friend. The query I would use for this problem statement would be a cts:document-query();
An Example:
cts:values(
cts:collection-reference(),
(),
(),
cts:document-query('/path/to/my/document')
)
Full Example:
cts:search(
collection(),
cts:collection-query(
cts:values(
cts:collection-reference(),
(),
(),
cts:document-query('/path/to/my/document')
)
)
)[1 to 10]
Option two: use cts:collection-match()
Need more control over returning just some of the collections from a document, then use cts:colection-match(). Like the first option, you can restrict the results to just some fragments. However, it has the benefit of having an option for a pattern.
Attention:
They both return a sequence - perfect for feeding into other parts of your query. However, under the hood, I believe they work differently. The second option is run against a lexicon. The larger the list of unique collection names and the more complex your pattern match, the longer for resolution. I use collection-match in projects. However, I usually use it when I can limit the possible choices by restricting the results to a smaller number of documents.
You can't do this in a single step. You have to run code first to retrieve collections associated with a document. You can use something like xdmp:document-get-collections for that. You then have to feed that into a cts query that you build dynamically:
let $doc-collections := xdmp:document-get-collections($doc-uri)
return
cts:search(collection(), cts:collection-query($doc-collections))[1 to 10]
HTH!
Are you looking for cts:collection-query()?
Insert two XML files to the same collection:
xquery version "1.0-ml";
xdmp:document-insert("/a.xml", <root><sub1><a>aaa</a></sub1></root>,
map:map() => map:with("collections", ("coll1")));
xdmp:document-insert("/b.xml", <root><sub2><a>aaa</a></sub2></root>,
map:map() => map:with("collections", ("coll1")));
Search the collection:
xquery version "1.0-ml";
let $myColl:= xdmp:document-get-collections("/a.xml")
return
cts:search(/root,
cts:and-query((cts:collection-query($myColl),cts:element-query(xs:QName("a"),"aaa")
)))
I have 2 nodes, which needs to call one function - it's common place in programming.
I suppose, there is no way in node-red to call the function, except "wiring" Function nodes sequentially.
Well, I did try it, but with no success.
Please look(copy_paste) at my flow and give help:
[{"id":"d86b4b3b.0670d8","type":"inject","z":"901492e5.e9666","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":169,"y":224,"wires":[["1a6b10c8.0788cf"]]},{"id":"1a6b10c8.0788cf","type":"function","z":"901492e5.e9666","name":"func0","func":"if(msg.payload.second_call){return [null,msg];}\nelse {msg.payload[\"second_call\"] = true;\nmsg.payload[\"count\"] = 0;\nreturn [msg,null];\n}\n","outputs":"2","noerr":0,"x":350,"y":223,"wires":[["577ae7e1.0c1948"],["b2204e3f.44cef"]]},{"id":"577ae7e1.0c1948","type":"function","z":"901492e5.e9666","name":"func1","func":"msg.payload.count++;\nreturn msg;","outputs":1,"noerr":0,"x":352,"y":316,"wires":[["1a6b10c8.0788cf"]]},{"id":"4e8f3348.10ab0c","type":"debug","z":"901492e5.e9666","name":"","active":true,"console":"false","complete":"payload","x":783.5,"y":332,"wires":[]},{"id":"b2204e3f.44cef","type":"function","z":"901492e5.e9666","name":"func3","func":"msg.payload.count++;\nreturn msg;","outputs":1,"noerr":0,"x":619,"y":332,"wires":[["4e8f3348.10ab0c"]]},{"id":"5bf50c74.5376e4","type":"inject","z":"901492e5.e9666","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":160,"y":422,"wires":[["c9b5e6b.ae91818"]]},{"id":"c9b5e6b.ae91818","type":"function","z":"901492e5.e9666","name":"func10","func":"if(msg.payload.second_call){return [null,msg];}\nelse {msg.payload[\"second_call\"] = true;\nmsg.payload[\"count\"] = 0;\nreturn [msg,null];\n}\n","outputs":"2","noerr":0,"x":345,"y":422,"wires":[["f11eb781.083348"],["b2204e3f.44cef"]]},{"id":"f11eb781.083348","type":"function","z":"901492e5.e9666","name":"func11","func":"msg.payload.count+=10;\nreturn msg;","outputs":1,"noerr":0,"x":348,"y":508,"wires":[["c9b5e6b.ae91818"]]}]
There are a few of options here.
If you are going to use the "function" multiple time then you could wrap it up in a sub-flow. This means that there is one copy of the code to edit and you can chain this into flows that do not have a common end.
If you are not going to have to change the "function" at all once it's written you can add it to the functionGlobalContext in the settings.js. This will let you include it in a given function node. See the doc for how to use the context. This does mean that you can't change the code without restarting Node-RED
I have been digging through IBM knowledge center and have returned frustrated at the lack of definition to some of their scripting interfaces.
IBM keeps talking about a containment path used in their id definitions and I am only assuming that it corresponds to an xml element within file in the websphere config folder hierachy, but that's only from observation. I haven't found this declared in any documentation as yet.
Also, to find an ID, there is a syntax that needs to be used that will retrieve it, yet I cannot find a reference to the possible values of 'types' used in the AdminConfig.getid(...) function call.
So to summarize I have a couple questions:
What is the correct definition of the id "heirachy" both for fetching an id and for the id itself?
e.g. to get an Id of the server I would say something like: AdminConfig.getid('/Cell:MYCOMPUTERNode01Cell/Node:MYCOMPUTERNode01/Server:server1'), which would give me an id something like: server1(cells/MYCOMPUTERNode01Cell/nodes/MYCOMPUTERNode01/servers/server1|server.xml#server_1873491723429)
What are the possible /type values in retrieving the id from the websphere server?
e.g. in the above example, /Cell, /Node and /Server are examples of type values used in queries.
UPDATE: I have discovered this document that outlines the locations of various configuration files in the configuration directory.
UPDATE: I am starting to think that the configuration files represent complex objects with attributes and nested attributes. not every object with an 'id' is query-able through the AdminConfig.getid(<containment_path>). Object attributes (and this is not attributes in the strict xml sense as 'attributes' could be nested nodes with a simple structure within the parent node) may be queried using AdminConfig.showAttribute(<element_id>, <attribute_name>). This function will either return the string value of the inline attribute of the element itself or a string list representation of the ids of the nested attribute node(s).
UPDATE: I have discovered the AdminConfig.types() function that will display a list of all manipulatible object types in the configuration files and the AdminConfig.parent() function that displays what nodes are considered parents of the specified node.
Note: The AdminConfig.parent() function does not reveal the parents in order of their hierachy, rather it seems to just present a list of parents. e.g. AdminConfig.parent('JDBCProvider') gives us this exact list: 'Cell\nDeployment\nNode\nServer\nServerCluster' and even though Server comes before ServerCluster , running AdminConfig.parent('Server') reveals it's parents as: 'Node\nServerCluster'. Although some elements can have no parents - e.g. Cell - Some elements produce an error when running the parent function - e.g. Deployment.
Due to the apparent lack of a reciprocal AdminConfig.children() function, It appears as though obtaining a full hierachical tree of parents/children lies in calling this function on each of the elements returned from the AdminConfig.parent(<>) call and combining the results. That being said, a trial and error approach is mostly fruitful due to the sometimes obvious ordering.
To iterate over the properties of an Object in AS3 you can use for(var i:String in object) like this:
Object:
var object:Object = {
thing: 1,
stuff: "hats",
another: new Sprite()
};
Loop:
for(var i:String in object)
{
trace(i + ": " + object[i]);
}
Result:
stuff: hats
thing: 1
another: [object Sprite]
The order in which the properties are selected however seems to vary and never matches anything that I can think of such as alphabetical property name, the order in which they were created, etc. In fact if I try it a few different times in different places, the order is completely different.
Is it possible to access the properties in a given order? What is happening here?
I'm posting this as an answer just to compliment BoltClock's answer with some extra insight by looking directly at the flash player source code. We can actually see the AVM code that specifically provides this functionality and it's written in C++. We can see inside ArrayObject.cpp the following code:
// Iterator support - for in, for each
Atom ArrayObject::nextName(int index)
{
AvmAssert(index > 0);
int denseLength = (int)getDenseLength();
if (index <= denseLength)
{
AvmCore *core = this->core();
return core->intToAtom(index-1);
}
else
{
return ScriptObject::nextName (index - denseLength);
}
}
As you can see when there is a legitimate property (object) to return, it is looked up from the ScriptObject class, specifically the nextName() method. If we look at those methods within ScriptObject.cpp:
Atom ScriptObject::nextName(int index)
{
AvmAssert(traits()->needsHashtable());
AvmAssert(index > 0);
InlineHashtable *ht = getTable();
if (uint32_t(index)-1 >= ht->getCapacity()/2)
return nullStringAtom;
const Atom* atoms = ht->getAtoms();
Atom m = ht->removeDontEnumMask(atoms[(index-1)<<1]);
if (AvmCore::isNullOrUndefined(m))
return nullStringAtom;
return m;
}
We can see that indeed, as people have pointed out here that the VM is using a hash table. However in these functions there is a specific index supplied, which would suggest, at first glance, that there must then be specific ordering.
If you dig deeper (I won't post all the code here) there are a whole slew of methods from different classes involved in the for in/for each functionality and one of them is the method ScriptObject::nextNameIndex() which basically pulls up the whole hash table and just starts providing indices to valid objects within the table and increments the original index supplied in the argument, so long as the next value points to a valid object. If I'm right in my interpretation, this would be the cause behind your random lookup and I don't believe there would be any way here to force a standardized/ordered map in these operations.
Sources
For those of you who might want to get the source code for the open source portion of the flash player, you can grab it from the following mercurial repositories (you can download a snapshop in zip like github so you don't have to install mercurial):
http://hg.mozilla.org/tamarin-central - This is the "stable" or "release" repository
http://hg.mozilla.org/tamarin-redux - This is the development branch. The most recent changes to the AVM will be found here. This includes the support for Android and such. Adobe is still updating and open sourcing these parts of the flash player, so it's good current and official stuff.
While I'm at it, this might be of interest as well: http://code.google.com/p/redtamarin/. It's a branched off (and rather mature) version of the AVM and can be used to write server-side actionscript. Neat stuff and has a ton of information that gives insight into the workings of the AVM so I thought I'd include it too.
This behavior is documented (emphasis mine):
The for..in loop iterates through the properties of an object, or the elements of an array. For example, you can use a for..in loop to iterate through the properties of a generic object (object properties are not kept in any particular order, so properties may appear in a seemingly random order)
How the properties are stored and retrieved appears to be an implementation detail, which isn't covered in the documentation. As ToddBFisher mentions in a comment, though, a data structure commonly used to implement associative arrays is the hash table. It's even mentioned in this page about associative arrays in AS3, and if you inspect the AVM code as shown by Ascension Systems, you'll find exactly such an implementation. As described, there is no notion of order or sorting in typical hash tables.
I don't believe there is a way to access the properties in a specific order unless you store that order somehow.
Could anyone explain what node means in MySQL?
This one is talking about nested set.
I am reading a document from Codeigniter's wiki and I am not sure what I am supposed to add for $node.
getSubTreeAsHTML (line 704)
Renders the fields for each node starting at the given node
* return: Sample HTML render of tree
string getSubTreeAsHTML (array $node, [array $fields = array()])
* array $node: The node to start with
* array $fields: The fields to display for each node
The code you are looking at is part of BackendPro. The full code of the function can be viewed here.
"Node" in this case refers to a data node of a nested set. Nested sets are nice because they allow you to quickly select a whole branch of a hierarchy with only the starting node.
It looks like the function specified renders part of a tree in HTML starting at the node you specify. The BackendPro interface must render hierarchical data somewhere.
EDIT: Nested sets are not a MySQL-only concept, but there is a good article about nested sets and MySQL here:
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/