I have the following for-each select;
"sc:item($myFolder,.)/descendant::item [#template='myTemplate']". According to Sitecore's own profiler this returns crawls through 16.000 items, although there are only approx 1700 items with the mentioned template.
Could this be optimized - if so, how?
The for-each is not the problem, but the XPath query used is.
The descendant axis is usually expensive because it requires the engine to do a complete deep search, without the possibility of eliminating paths. So you may want to replace this with a pattern which restricts the required search path.
Maybe using keys would help, but without deeper knowledge of the XML to be processed and the operations performed this is hard to tell.
If you can convert your xsl:for-each to a xsl:template, it should help with performance, as most XSLT processors are optimized for template matching.
"Do you have an example of this? It's a basic for-each that select a list of items based on the template, and then sort by a number field and shows the 3 top (so its basicly a top 3 list)"
Based on what you're trying to accomplish, I think you would be much better off putting this logic into a save handler and organizing your items when a content author saves an item based on the template you're looking for.
For example (and this is a very rough example), create a "Top 3" folder in your content tree. Then, write a save handler that checks the TemplateID of an item as it's being saved. If the saved item's TemplateID matches the TemplateID you're looking for, select all the items in your tree based on the TemplateID and process them with whatever sorting logic you need. As you find an item that belongs in the "Top 3" folder, move the item to the "Top 3" folder.
Then, in your rendering code, you simply have to get the "Top 3" folder and retrieve it's children. This will be MUCH faster than attempting to look through 1700 items every time the rendering is loaded.
If I need to do any particularly difficult searches in an XSLT, then I often define an XSLT helper method to perform the search, as the .Net API has much better facilities available.
In your case, I'd consider creating a .Net function to do the job, either using the Link Manager (as Mark Cassidy suggests) or using Sitecore fast queries to retrieve the items (fast queries are parsed and run as SQL queries).
To register a class as an XML Extension Method library, open web.config, locate the /configuration/sitecore/xslExtensions node and add an entry with your class' full type name and an XML namespace (the URL doesn't actually have to exist).
To use your function, register it in the namespaces at the top of your XSLT (and remember to add the namespace to the exclude-result-prefixes stylesheet attribute). You should then be able to call `namespace:YourFunction().
For more detailed information on XSLT extension methods, see the presentation component reference, page 40.
The reason the XSLT crawls through 16,000 items when you only have 1700 matches is that the 16,000 represents the number of nodes tested, not the number of nodes returned. Sitecore XSLT performance is dependent on your actual data structure, if you have a flat structure with lots of nodes (e.g. everything in one folder) all xslt processing will suffer. You might consider optimising your data structure into something deeper and more branched to aid XSLT performance. I believe Sitecore themselves recommend that you have no more than 100 items in any location (i.e. never more than 99 siblings for any item).
It can be optimised, but the easiest approach would be to reorganize your content architecture to better suit your needs and requirements.
Straight from XSLT there is no easy solution, but with a bit of coding you can fAirly easily get all your content items based on your specific template. It would look something like this:
Item myTemplate = Sitecore.Context.Database.GetItem( "id-of-your-template" );
LinkItem[] li = Sitecore.Globals.LinkDataBase.GetReferrers( myTemplate );
// li now holds a list of LinkItem for items that are based on your template
List<Item> myItems = new List<Item>();
foreach( LinkItem l in li )
myItems.Add( li.SourceItem() );
// your additional processing/filtering here
Keep in mind, this is a very non-specific example of how this can be achieved. I would need to know a lot more about your solution to come up with a better response. And I still feel, the best approach is probably still to look at your information architecture.
Related
In the root template page.10 is already taken. If I put page.10 into my extension template, I override it. How can I make sure (just putting a large number is not "making sure") that I don't override anything? The root template is very complicated and includes many other templates, so I cannot really tell which numbers are already taken. I just want to use the extension template to append some content.
The safest solution would be not adding anything automatically. Instead you could provide your rendering instruction via lib.* or tt_content.list.* in case it is a registered plugin:
lib.yourContent = USER_INT
lib.yourContent { ... }
Then you only need to document how to add something to the page output, e.g.:
page.11 < lib.yourContent
I know it has been a while since you've asked this question.
You're saying "just putting a large number is not making sure" because you have no idea what content is using which number on the page object.
If you want to be 99,9% sure that a number has not been used, why don't you use the current timestamp as a number on this cObject? That's how the TYPO3 Errorhandler also refers to pages, using the timestamp they wrote it.
The simpliest answer if you can make sure which Page object index is already used for something is you cannot.
It might be set somewhere deeper in extensions, in any condition that meets any expression is defined there.
None of standard built in tools in TYPO3 can predict that and check all combinations of conditions to tell you if such number is set somewhere in some case.
But.
If you are an admin of that page, then the best approach is just to know your template.
Analyse the typoscript and know what numbers in Page object are used for something. Make a tidy consistent template, clean it up, check using Template tools -> Typoscript object browser. You have to know what's going on on your site, the elements in indexes of main Page object are the main and basis things which are shown public.
(Or just guess any random big number and try to search it in whole typoscript using Template tools -> Template Analyzer -> View complete TS listing. Let's be honest, probability that you shoot a big number which is already used is rather low)
I need help with creating UseCase template for Enterprise Architect (v 12.1). I have UseCase diagram like this one and I need to generate documentation from diagram named "Transaction" (as you can see on this picture):
The problem is, that one UseCase is located in another package. When generating documentation with my template (I need only " Transaction" package in my documentation not Transaction Validation or other packages), the UseCase of Transaction Validation is not generated (simply because of this element is from another package).
One more note - we don't write Structured Specification Scenario, but we write scenarions into "Description" tab. Like this one:
I tried to create template for generating elements located on diagram, but there is only option to generate Element.StructuredScenarioText for "foreign" element located on diagram when creating template (I need the red one values - ElemScenario.Scenario, ElemScenario.Type and ElemScenario.Notes):
Is there any option to generate Scenario (not structured) for "foreign" UseCase located on diagram?
Thanks for your help!
In order to include the description from an element's scenarios, select the RTF template section package / element / scenario and insert the Notes field.
Your other issue, how to include elements from other packages in a report, is a little trickier.
Normally you would base the template on the diagram and make sure you select Include all Diagram Elements in Report in the Generate Documentation dialog.
The problem in this case is that when you document elements in the context of a diagram, you only have access to a limited subset of the element fields. For scenarios, you're limited to the Element.StructuredScenarioText field, which in your case is empty. The same limited set of fields is available if you document elements in the context of a connector, ie elements connected to the element being documented, so you can't use that either.
The simplest option is to create a template fragment. With fragments you can implement your own selection using an SQL query or a custom script, and thus free your document from the package hierarchy.
Alternatively, you can run the generation from a higher package level which includes all your use cases (in your case, "Transactions in WO"), and add a filter in the Generate Documentation dialog to select only those use cases you want.
I have a Sitecore 6.6 solution running MVC and Razor.
I am have the following line;
#Html.Raw(Sitecore.Context.Database.GetItem(myList.Children.LastOrDefault()["myField1"]).Fields["myField2"])
The above works fine, except the order it sorts in. I need to get the latest item based on the __Created field. LastOrDefault seems to take the last item in the tree, which does not always correspond to the actual latest created item.
Can it be done in one line as the above?
How about this:
myList.GetChildren()
.OrderBy(x => x[Sitecore.FieldIDs.Created])
.Reverse()
.LastOrDefault()
I guess this would work too:
myList.GetChildren()
.OrderBy(x => x.Statistics.Created)
.Reverse()
.LastOrDefault()
Keep in mind though that first all the children will be retrieved and then the sorting will happen.
If you have a lot of children it will be slow.
One general note, you shouldn't do this in the View really. You're putting too much logic in there. Your model should provide the item that you need (last created).
I have an xsl file which I am currently grabbing all of the records from at once, starting them off as hidden and showing them as the user selects an id (<xsl:for-each select"">). The id value is currently being stored as a javascript variable selected by a user clicking that id.
I would like to use xQuery to grab the records, but only the records which match the ID the user has selected. Furthermore I generally understand the logic behind the rules in xQuery i just don't understand how to actually use it in my xsl file. Is it possible to use xQuery to maybe compare the value of the id(a js variable) to something using xQuery to grab only the records with that matching id?
Thank you for your time,
XQuery is a separate language from XSLT, not one that's embedded within XSLT. So depending on how you are launching XSLT, you can look for a parallel method for launching XQuery. For example, you may try XQIB (I have not tried it, but it looks promising).
If you need more help on that, let us know how you are running an XSLT processor, and what your data source is.
HOWEVER... It's not at all clear that XQuery is really what you want. It doesn't sound like you're wanting XQuery for something that you couldn't already do in XSLT. I'm not even sure you're not thinking of jQuery... which is a completely different animal.
It would be helpful if you could tell us more about where the records are coming from; what form they're stored in (an XML DOM?); and what you need to do with them. Probably the best solution then is that we show you how to do what you're trying to do within XSLT (or in Javascript).
Update
Looking at your new comment, I realize that I may have misunderstood where you are trying to run XQuery. You mentioned javascript above, from which I assumed you wanted to run XQuery in the browser, but now I think I jumped to the wrong conclusion - you are actually wanting to run it on the server maybe?
Regardless of where you're running it, either XSLT or XQuery can select "only the records which match the ID the user has selected". But if the XSLT/XQuery is running on the server, in order for this to work, you have to have either a page refresh or an AJAX call after the user selects an ID, to let the program on the server know what the selected ID is. I'm not sure if you already have that architecture set up, or if you're still trying to figure out how to use an AJAX call to retrieve data based on user input.
It sounds like you want to never send the whole set of records from server to client, not even initially (correct?). In that case, how does the user know what the set of available IDs is?
Anyway, you question may boil down to "How do you run XQuery from ASP.NET?" I have not tried to do that, but this article may help: Using Saxon.NET in ASP.NET; or this one: Querying XML Data with XQuery.
But again, I think XQuery may not be what you want. XQuery is not a querying language used within XSLT - that's more like XPath. XQuery is something you would use instead of XSLT, or beside it. So if you're using XSLT and you want to filter records according to what ID the user has selected, assuming you already know what ID the user has selected, the easy way to do that is within XSLT/XPath, rather than firing up a separate processor. E.g. you could say
<xsl:for-each select="//record[#ID = $usersChosenID]"> ...
Let me know if this is getting close to a solution for you. There are a variety of directions to expand this explanation, but I don't want to spend time scratching where there's no itch.
I'm trying to display a directory tree from a a treebeard model. The annotated list method suggested in the treebeard tutorial works fine, but I'd like to include id information in the data tree.
The dump_bulk() has all the info I need, but as a python and django newbie I'm strugglling to find a way to extract the information and display it in the template.
I've thought about switching to javascript, and parsing the json string, but javascript doesn't like the u prefix before the string values. Is there a simple way to avoid the u prefix?
I've also thought about writing a function based on the get_annotated_list() that does include id information. I'm assuming it should be possible to overload the get_annotated_ list so that id information is included, but I'm not too sure how to tackle that either.
Any and all suggestions to help me progress along the learning curve will be appreciated.
As you probably know, get_annotated_list() will return an array of tuples, in the form (node, info). info is just a dictionary, so you can iterate over the list, and add any additional key-pairs you like. E.g.,
for node, info in my_annotated_list:
info['foo'] = node.id
Pass this to your template, and you should be fine.
You can also use a generator. This is from a project I'm working on right now:
def annotated_menu_items(initial_header, menu_items):
headings = [initial_header]
for item, info in menu_items:
yield item, info, item.is_leaf(), headings[-1:][0]
if info['open']:
headings.append(item.title)
for close in info['close']:
headings.pop()
Here, I'm adding as extra info whether the node in question is a leaf, and pushing the title from the most recently opened node onto a stack so I can access it from deeper levels of the tree.
You say you're new to Python, so you may want to read up on generators. They you materialize the elements of a (potentially infinite) list lazily. In order to use it, you invoke the function which constructs the generator, then you can treat the generator object as an iterable. E.g.,
my_fancy_menus = annotated_menu_items("My Menu", my_annotated_list)
for menu in my_fancy_menus:
do_stuff(menu)
You can also pass generators to Django templates, where they are treated like lists.