I have a webService that returns certain values.
<BasicPersons>
<id>4</id>
<firstName>Patricia</firstName>
<middleName>A</middleName>
<lastName>Cluss</lastName>
</BasicPersons>
<BasicPersons>
<id>5</id>
<firstName>Benjamin</firstName>
<middleName>L</middleName>
<lastName>Handen</lastName>
</BasicPersons>
<BasicPersons>
<id>6</id>
<firstName>Ellen</firstName>
<lastName>Frank</lastName>
</BasicPersons>
<BasicPersons>
I know what some of those values will be but i don't know the order of the nodes. I want to assert that one of the "basicPersons" node contain firstname=Benjamin. How can i do it?
You do not need to know the order of nodes, just */BasicPersons[firstName='Benjamin'] -- it searches every child of basicPerson where text is exactly Benjamin.
upd: some helpful link Using XPATH to search text containing
upd2: thank you guys for editing, I've missed firstname tag
You could use an XPath assertion like:
exists(//*:BasicPersons[contains(*:firstName, 'Benjamin')])
Related
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
I am running ft:query on a collection which is stored in eXist-db but it's returning zero results. If I use fn:contains function it works perfect but ft:query returns zero results. Below is my XML structure, index configuration file, and query:
test.xml
<article xmlns="http://www.rsc.org/schema/rscart38"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
type="ART"
xsi:schemaLocation="http://www.rsc.org/schema/rscart38 http://www.rsc.org/schema/rscart38/rscart38.xsd" dtd="RSCART3.8">
<metainfo last-modified="2012-11-23T19:16:50.023Z">
<subsyear>1997</subsyear>
<collectiontype>rscart</collectiontype>
<collectionname>journals</collectionname>
<docid>A605867A</docid>
<doctitle>NMR studies on hydrophobic interactions in solution Part
2.—Temperature and urea effect on
the self-association of ethanol in water</doctitle>
<summary/>
</article>
collection.xconf
<collection xmlns="http://exist-db.org/collection-config/1.0">
<index rsc="http://www.rsc.org/schema/rscart38"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
type="ART"
xsi:schemaLocation="http://www.rsc.org/schema/rscart38 http://www.rsc.org/schema/rscart38/rscart38.xsd"
dtd="RSCART3.8">
<fulltext default="all" attributes="false"/>
<lucene>
<analyzer id="nosw" class="org.apache.lucene.analysis.standard.StandardAnalyzer">
<param name="stopwords" type="org.apache.lucene.analysis.util.CharArraySet"/>
</analyzer>
<text qname="//rsc:article" analyzer="nosw"/>
</lucene>
<create path="//rsc:doctitle" type="xs:string"/>
<create path="//rsc:journal-full-title" type="xs:string"/>
<create path="//rsc:journal-full-title" type="xs:string"/>
</index>
</collection>
test.xq
declare namespace rsc="http://www.rsc.org/schema/rscart38";
let $coll := collection('/db/apps/test/RSC')
let $hits := $coll//rsc:doctitle[ft:query(., 'studies')]
return
$hits
Let's start from your query. The key part of your query is:
$coll//rsc:doctitle[ft:query(., 'studies')]
This performs a full text query for the string studies on rsc:doctitle elements in the collection. For this ft:query() function to work, there must be an index configuration for the named elements. This brings us to your index configuration.
In your index configuration, you have a full text (Lucene) index:
<text qname="//rsc:article" analyzer="nosw"/>
A couple of issues:
The #qname attribute should be a QName - simply, an element or attribute name. You've expressed this as a path. Remove the path //, leaving just rsc:article.
Your code does a full text query on rsc:doctitle, not on rsc:article, so I would expect your code, as written, to return 0 results. Change the existing index to rsc:doctitle, or add a new index on rsc:doctitle so that you could query either one. Reindex the collection afterwards, and as Adam suggested, check the Monex app's Indexing pane to ensure that the database has applied your index configuration as expected.
Lastly, contains() does not require an index to be in place. It benefits from the presence of a range index (i.e., your <create> elements), but range indexes are quite different from full text indexes. To learn more about these, I'd suggest reading the eXist documentation on indexing, http://exist-db.org/exist/apps/doc/indexing.xml.
I am not certain if configuring a Standard Analyzer without stopwords in the way you have done is correct. Can you check with Monex that your index has your terms in it?
Note also, if you created the index config after loading the index, then you need to reindex the collection. When you reindex it is also worth monitoring $EXIST_HOME/webapp/WEB-INF/exist.log to ensure that the indexing is done as expected.
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.
I want to show some data from an xml file inside a datagrid, so I do this:
<mx:AdvancedDataGrid id="dgDomains" dataProvider="{new XMLListCollection(xmlDomains..domain(deleted.toString() != '1'))}"
...
and the xml data looks like this:
<domains>
<domain>
<domainName>AGRICULTURE</domainName>
<deleted>1</deleted>
</domain>
<domain>
<domainName>IT</domainName>
<deleted/>
</domain>
</domains>
The filter fails if the "deleted" node isn't there. I get this error: Variable deleted is not defined.
Can someone help me improve the filter so that it will work in this case, too?
Thank you!
Its fails with error because filter can't apply's on null/undefined variables in your case delete,
you may uses XML's elements function it will take care of null/undefined value
xmlDomain..domain.(elements('deleted') != '1')
above statement also return's all nodes in which delete is not defined
Hopes that helps
is it possible to follow a link by it's class name instead of the id, text or title? Given I have (haha, cucumber insider he?) the following html code:
<div id="some_information_container">
Translation here
</div>
I do not want to match by text because I'd have to care about the translation values in my tests
I want to have my buttons look all the same style, so I will use the CSS class.
I don't want to assign a id to every single link, because some of them are perfectly identified through the container and the link class
Is there anything I missed in Cucumber/Webrat? Or do you have some advices to solve this in a better way?
Thanks for your help and best regards,
Joe
edit: I found an interesting discussion going on about this topic right here - seems to remain an open issue for now. Do you have any other solutions for this?
Here's how I did it with cucumber, hope it helps. The # in the step definition helps the CSS understand whats going on.
This only works with ID's not class names
Step Definition
Then /^(?:|I )should see ([^\"]*) within a div with id "([^\"]*)"$/ do |text, selector|
# checks for text within a specified div id
within "##{selector}" do |content|
if defined?(Spec::Rails::Matchers)
content.should contain(text)
else
hc = Webrat::Matchers::HasContent.new(text)
assert hc.matches?(content), hc.failure_message
end
end
end
Feature
Scenario Outline: Create Project
When I fill in name with <title>
And I select <data_type> from data_type
And I press "Create"
Then I should see <title> within a div with id "specifications"
Scenarios: Search Terms and Results
| data_type | title |
| Books | A Book Title |
Here is how to assert text within an element with the class name of "edit_botton"
Then I should see "Translation here" within "[#class='edit_button']"
How about find('a.some-class').click?
I'm not very familiar with the WebRat API, but what about using a DOM lookup to get the reference ID of the class that you are looking for then passing that to the click_link function?
Here's a link to some javascript to retrieve an item by class.
http://mykenta.blogspot.com/2007/10/getelementbyclass-revisited.html
Now that I think about it, what about using Javascript to just simply change it to some random ID then clicking that?
Either way, that should work until the frugal debate of a name to include the getbyclass function as is resolved.
Does have_tag work for you?
have_tag('a.edit_button')