Reading menu items from XML in asp.net - asp.net

I am building a multilingual web site which will provide four languages. I will be using an asp:MenuItem control. For each language I want to read menu items' names from an XML document.
XML draft can be thought as the following:
<root>
<language>
<en>
<home>
<link>Default.aspx</link>
<text>Home</text>
</home>
<about>
<link>About.aspx</link>
<text>About</text>
</about>
</en>
<de>
<home>
<link>Default.aspx</link>
<text>Hauptseite</text>
</home>
<about>
<link>About.aspx</link>
<text>Über</text>
</about>
</de>
</language>
</root>
I am not sure if the syntax and construction are correct. My other goal is about menu items order. The order must be same for all languages.
I want to know how to realize this. OR is there another and/or better way to do this.
Also my database is ready for content for both languages.
I do not want to work with if-else conditions. Thanks for your help.

If all languages should be the same structure, I would suggest a slightly different XML.
This groups the different names for the different languages together, which should be easier to manage should you need to change anything.
<root>
<item>
<link>default.aspx</link>
<text>
<en>Home</en>
<de>Hauptseite</de>
</text>
</item>
<item>
<link>about.aspx</link>
<text>
<en>About</en>
<de>Über</de>
</text>
</item>
</root>

Related

SAPUI5: Binding Attributes of XMLModels

How is this done in OpenUI 5 / SAPUI5?
given the following
<MainNavigation>
<Link>
<property name="Name">Clinical Overview</property>
<property name="command">showTeachingPoints</property>
<property name="autoSelect">true</property>
</Link>
<Link>
<property name="command">showDevices</property>
<property name="Name">Equipment</property>
</Link>
</MainNavigation>
And trying to fill out the text property for the following:
<tnt:SideNavigation expanded="true" itemSelect="onItemSelect">
<tnt:NavigationList id="sideMenu" items="{/MainNavigation/Link}">
<tnt:NavigationListItem text="{property/[#name='Name']/text()}" />
</tnt:NavigationList>
</tnt:SideNavigation>
The goal should be to display the Name of each property (so Clinical Overview, Equipment, etc...) but the query is not working.
Also I've tried:
{property/[#name='Name']/text()}
{property/[name='Name']/text()}
{property/['#name='Name'']/text()}
{property[#name='Name']/text()}
The only way that's worked has been
{property}
However that will only display whatever is first in the collection of property nodes. I want to know how to get at a specific node since I want to use the other nodes for different purposes (default selection, function callback names, etc...)
edited to clarify:
The list should contain:
Clinical Overview
Equipment
Using {property/#name} the list would be:
Name
command
Granted this is not what I'm looking for but it shares the same problem as {property} in that it returns only the first item under <Link> when I may want the second or third.
This xpath query works in other places /UI/MainNavigation/Link/property[#name='Name']/text() and I would just like to how to translate that into OpenUI.
This should do the trick:
<tnt:SideNavigation expanded="true" itemSelect="onItemSelect">
<tnt:NavigationList id="sideMenu" items="{/MainNavigation/Link}">
<tnt:NavigationListItem text="{property/#name}" />
</tnt:NavigationList>
</tnt:SideNavigation>
More info in the docs about Binding Path Syntax for XML Models.
For attributes, a special selector using the "#" character exists and "text()" can be used to reference the content text of an element. Lists are referenced by using the path to the multiple element.
BR Chris

Improve performance of query with range indexes in eXist-db

Reading the docs http://exist-db.org/exist/apps/doc/indexing.xml
I'm finding difficult to understand how and if I can improve the performances of a 'read' query (with 2 parameters: a string and an integer).
Do eXist-db have a default structural index? Can I improve a 2 params query with a 'range index'?
More details about my XML db (note there are 2 different dbs simply merged on the same root):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<db>
<docs>
<doc>
<header>
<year>2001</year>
<number>1</number>
<type>O</type>
</header>
<metas>
<meta>
<number>26001</number>
<details>
<detail>
<description>legge</description>
<number>19</number>
<date>14/01/1994</date>
</detail>
<detail>
<description>decreto legge</description>
<number>453</number>
<date>15/11/1993</date>
</detail>
</details>
</meta>
</metas>
</doc>
<doc>
<header>
<year>2001</year>
<number>2</number>
<type>O</type>
</header>
<metas>
<meta>
<number>26002</number>
<details>
<detail>
<description>decreto legislativo</description>
<number>29</number>
<date>03/02/1993</date>
</detail>
</details>
</meta>
<meta>
<number>26016</number>
<details>
<detail>
<description>decreto legislativo</description>
<number>29</number>
<date>03/02/1993</date>
</detail>
</details>
</meta>
</metas>
</doc>
</docs>
<full_text_docs>
<doc>
<header>
<year>2001</year>
<number>1</number>
<type>O</type>
<president>ferrari</president>
</header>
<text>lorem ipsum ...
</text>
</doc>
<doc>
<header>
<year>2001</year>
<number>2</number>
<type>O</type>
<president>ferrari</president>
</header>
<text>lorem ipsum......
</text>
</doc>
</full_text_docs>
</db>
This is my xquery
xquery version "3.0";
let $doc := doc("/db//index_test/test_general.xml")//db/docs/doc
let $fulltxt := doc("/db//index_test/test_general.xml")//db/full_text_docs/doc
return <root> {
for $a in $doc[metas/meta/details/detail[date="03/02/1993" and number = "29"]]/header
return $fulltxt[header/year/text()=$a/year/text() and
header/number/text()=$a/number/text() and
header/type/text()=$a/type/text()
]
} </root>
Basically I simply find for the detail/number and detail/date that matches the input in the first db and take the results for querying the second db. The results are all the <full_text_header> documents that matches.
I would to know if I can create indexes for the fields number and date to improve performance. Note this is the ONLY query I need to optimize (the only I do on this db) obviously number and date changes :).
SOLUTION:
For a clear explanation read the joewiz answer. My problem was the correct recognition of the .xconf file. It have to be placed in /db/yourcollectiondir. If you're using eXide when you create the file you should select Xml type with template "eXist-db collection configuration". When you try to save the file you will see a prompt "Apply configuration?" then click 'ok'. Just then run this xquery xmldb:reindex('/db/yourcollectiondir').
Now if all it's right when you run an xquery involving an index you will see the usage in "Monitoring and profiling".
As that documentation page states, eXist does create a structural index for all XML stored in the database. This is not an index of values, though, so without further indexes, queries based on value (rather than structure) would involve a lookup of values in the DOM. As your data grows larger, looking up values in the DOM gets slower and slower. This is where value-based indexes, such a range index, saves the day. (For a fuller explanation, see the "Indexing" section of Wolfgang Meier's "Tuning the Database" article, which is essential for getting the most performance out of eXist.)
So, yes, you can create indexes for the <number> and <date> fields. I'd recommend the "new range" index, as described on that documentation page. Your collection.xconf file setting up these indexes would look like this:
<collection xmlns="http://exist-db.org/collection-config/1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<index>
<range>
<create qname="number" type="xs:integer"/>
<create qname="date" type="xs:string"/>
</range>
</index>
</collection>
You have to store this within the /db/system/config/ collection, in a subcollection corresponding to the location of your data in the database. So if your data is located in /db/apps/myapp/data, you would place this collection.xconf file in /db/system/config/db/apps/myapp/data.
Note that the configuration here would only affect the for clause's queries of date and number values, and not the predicates in the return clause, which depend on the values of <year> and <type> elements. So, to ensure your query maximized the use of indexes, you should declare indexes on these; it seems that xs:integer would be the appropriate type for each.
Lastly, I would suggest eliminating the /text() steps, which are completely extraneous. For more on the use/abuse of text(), see Evan Lenz's article, "text() is a code smell".
Update (2016-07-17): With the updated code sample above, I have a couple of additional suggestions. First, since the code is in /db/index_test, we will store our files as follows:
Assuming you're using eXide, when you store the collection.xconf file in a collection, eXide will prompt you to have a copy of the file placed in the correct location in /db/system/config. If you're not using eXide, you need to store the collection.xconf file there yourself.
Using the unmodified query, I can confirm that despite the presence of the collection.xconf file, monex shows no indexes are being applied:
Let's make a few modifications to the file to ensure indexes are properly applied:
xquery version "3.0";
<root> {
for $a in doc("/db/index_test/test_general.xml")//detail[date = "03/02/1993" and number = 29]/ancestor::doc/header
return
doc("/db/index_test/test_general.xml")/db/full_text_docs/doc
[
header/year = $a/year and
header/number = $a/number and
header/type = $a/type
]
} </root>
With these modifications, monex shows that indexes are applied to the comparisons in the for clause:
The insights here are derived from the "Tuning the Database" article. To get full indexing for all comparisons, you will need to define additional indexes and may need to make similar modifications to your query.
One final note: the version of monex you see in these pictures is using a feature I added this weekend, called "Tare", which tries to filter out other operations from the query profiling results in order to help the user see just the effects of their own query. This feature is still just a pull request, so running the current release version, you won't see identical results.

Marklogic xquery gives different result on different servers

I have an XML file, a query and two servers.
I loaded the xml file into both using mlcp ad put attribute range indexes on where I think they are needed.
Our dev server acts as I expected, but the TEST server gives back only the first map element in the document. Checked all db setting, reloaded the docs, re-indexed both servers no result...
The document looks like this:
<geo version="0.3" xmlns="http://www.nvsp.nl/geo-mapping">
<meta-data>
<!--Generated by DIKW for NetwerkVSP STTip-->
<dateCreated>2014-06-27 15:17:17.643318</dateCreated>
</meta-data>
<map ppc4_id="3902" wijk_id="390213">
<bruto>196</bruto>
<stickers>19</stickers>
<netto>177</netto>
<aktief>J</aktief>
</map>
<map ppc4_id="3902" wijk_id="3902B01">
<bruto>36</bruto>
<stickers>3</stickers>
<netto>33</netto>
<aktief>J</aktief>
</map>
<map ppc4_id="3902" wijk_id="3902K01">
<bruto>245</bruto>
<stickers>44</stickers>
<netto>201</netto>
<aktief>J</aktief>
</map>
<map ppc4_id="3903" wijk_id="390301">
<bruto>256</bruto>
<stickers>37</stickers>
<netto>219</netto>
<aktief>J</aktief>
</map>
with roughly another 35000 map elements following.
The XQuery intents to find maps with certain ppc4_id or wijk_id attributes like so:
xquery version "1.0-ml";
declare namespace gm = "http://www.nvsp.nl/geo-mapping";
let $p4_id := "6626"
let $wijk_id := "662601"
let $uri := '/data/map/geo-mapping.xml'
(: setup query:)
let $q2 := cts:element-attribute-value-query(xs:QName("gm:map"), xs:QName("ppc4_id"), $p4_id)
let $q3 := cts:element-attribute-value-query(xs:QName("gm:map"), xs:QName("wijk_id"), $wijk_id)
(: return map with wijk_id from geo:)
let $maps := cts:search(//gm:map,$q2,("unfiltered"))
return $maps
Now the DEV server finds appropriate results like:
<map ppc4_id="6626" wijk_id="662601" xmlns="http://www.nvsp.nl/geo-mapping">
<bruto>220</bruto>
<stickers>11</stickers>
<netto>209</netto>
<aktief>J</aktief>
</map>
element
<map ppc4_id="6626" wijk_id="662602" xmlns="http://www.nvsp.nl/geo-mapping">
<bruto>198</bruto>
<stickers>13</stickers>
<netto>185</netto>
<aktief>J</aktief>
</map>
... more map elements ...
But the TEST server gives back only the first map element from the doc! No matter what id I ask for.
The scary part is that is does not complain or give an error but gives back a wrong answer?
I'm observing the same with 7.0-2.3. What you effectively see happening is that the unfiltered search returns the fragment for the entire geo-mapping document. And for some reason the searchable expression is returning just the first map element within it on your test server. Maybe there is a version difference?
What you observe is caused by the 'unfiltered' option. Run filtered and it will work fine without any extra indexes. From the looks of it adding an attribute range index doesn't help, nor enabling positions, though I thought that should. Maybe Mike's suggestions can help investigate what is happening there.
What does help is add a fragment root for the map element. But I wouldn't recommend using fragmentation on such a large document. Split the geo-mapping into separate map documents. That makes getting accurate estimates much easier..
HTH!
You can use several tools to figure out what a query is doing. In this case https://docs.marklogic.com/xdmp:plan and https://docs.marklogic.com/xdmp:query-trace should help.
You could also try https://docs.marklogic.com/xdmp:query-meters but it's generally more useful for performance analysis.
Also it's often useful to https://docs.marklogic.com/xdmp:describe your results. Sometimes that reveals subtleties that don't show up in the XML or browser rendering.

In jjtree, is there a way to traverse the generated parse tree and track changes to the value

I'm new to JJTree parsing. I've gone through basics. In jjtree, is there a way to traverse the generated parse tree and track changes to the value?
Say for example I've a JJTree which produces the following tree structure:
<parent name="xx">
<child age="21" family="true">
</child>
<parent>
<parent name="xy">
<child age="21" family="true">
</child>
<parent>
Here, i'd like to change the family as "false" for parent having name "xy". I'm struggling in this part.
My code needs a similar change. As my code increases complexity to understand, I've given here a sample which is understandable.
To traverse the tree, you can use a visitor object. See the documentation.

RSS feed with nested items, what is the proper way?

I have a product that has multiple variations. I would like, in an RSS feed, to show this as a nested items option, but I don't know if this is valid or not:
<?xml version="1.0" encoding="US-ASCII" ?>
<rss version="2.0"
xmlns:s="http://example.com/s">
<channel>
<title>Examle RSS</title>
<link>http://www.example.com/</link>
<description>Example Product Feed</description>
<language>en-us</language>
<item>
<title>My Product</title>
<description>An amazing item!</description>
<item>
<title>AS-435</title>
<s:price>$34.00</s:price>
</item>
</item>
</channel>
</rss>
If this isn't valid what is the best way to go about this?
It's not valid, but it's a very interesting idea.
You'd have to put the inner items in a new namespace.
And keep in mind that no one else will understand what you're doing.
The rss schema definition for an <item> does not include the option for another <item> sub-element. (http://cyber.law.harvard.edu/rss/rss.html)
If the data only needs to be consumed only by your client's proprietary parser, why not drop the RSS schema and use a custom one?
Otherwise, if it would be of some benefit to be compatible with feed readers, why not create a feed for each type of item, web 2.0 style? For example, one for product lines, one for product models and one for product makes. Better make the feeds query-able, and identify each item with a unique id.
I in fact located this thread to promote my agenda.

Resources