<cars>
<car>
<name v="speedy"/>
<type v="sport"/>
<engine>
<hp>300</hp>
</engine>
<car>
<car>
<name v="biggo"/>
<type v="truck"/>
<engine>
<hp>190</hp>
</engine>
<car>
</cars>
I have a problem in building a xpath-term that gives my biggos horsepower.
I am not sure how to filter and get the value of something that is not in the filtered element.
Related
I have a set of assets which had a property "name".
I want to get a dynamic number of those assets and I should get it alphabetically sorted by that "name" property.
I query that with this query:
type=dam:Asset
path=/content/dam/en/foobar/contacts/
orderby=#jcr:content/data/master/#name
orderby.sort=asc
p.limit=3
and this is working, so in a set of names:
[Paloma, Abel, José, Eduardo]
it retrieves:
Abel, Eduardo, José.
The problem is with spanish alphabet, in which Á is the same letter as A.
So in a set of:
[Paloma, Abel, José, Álvaro, Eduardo]
it retrieves:
Abel, Eduardo, José.
Being Álvaro excluded because its not part of the first 3 elements after ordeby it, when in should be the second, it should retrieve:
Abel, Álvaro, Eduardo.
So, to fix that, I've created a custom oak lucene index like below:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:rep="internal"
jcr:mixinTypes="[rep:AccessControllable]"
jcr:primaryType="nt:unstructured">
<socialLucene/>
<workflowDataLucene/>
<slingeventJob/>
<jcrLanguage/>
<versionStoreIndex/>
<repMembers/>
<cqReportsLucene/>
<commerceLucene/>
<counter/>
<authorizables/>
<enablementResourceName/>
<externalPrincipalNames/>
<cmLucene/>
<foobarCFIndexFilter
jcr:primaryType="oak:QueryIndexDefinition"
async="[async,nrt]"
evaluatePathRestrictions="{Boolean}true"
includedPaths="[/content/dam/es/foobar,/content/dam/en/foobar]"
queryPaths="[/content/dam/es/foobar,/content/dam/en/foobar]"
reindex="{Boolean}false"
reindexCount="{Long}24"
seed="{Long}3850652403740003290"
type="lucene">
<analyzers jcr:primaryType="nt:unstructured">
<default jcr:primaryType="nt:unstructured">
<filters jcr:primaryType="nt:unstructured">
<Synonym
jcr:primaryType="nt:unstructured"
format="solr"
synonyms="synonyms.txt">
<synonyms.txt/>
</Synonym>
</filters>
<tokenizer
jcr:primaryType="nt:unstructured"
name="Classic"/>
</default>
</analyzers>
<indexRules jcr:primaryType="nt:unstructured">
<nt:base jcr:primaryType="nt:unstructured">
<properties jcr:primaryType="nt:unstructured">
<title
jcr:primaryType="nt:unstructured"
analyzed="{Boolean}true"
isRegexp="{Boolean}false"
name="jcr:content/data/master/title"
nodeScopeIndex="{Boolean}true"
ordered="{Boolean}true"
propertyIndex="{Boolean}true"
type="String"/>
<date
jcr:primaryType="nt:unstructured"
name="jcr:content/data/master/date"
ordered="{Boolean}true"
propertyIndex="{Boolean}true"/>
<sectors
jcr:primaryType="nt:unstructured"
name="jcr:content/data/master/sectors"
propertyIndex="{Boolean}true"/>
<contentFragment
jcr:primaryType="nt:unstructured"
name="jcr:content/contentFragment"
propertyIndex="{Boolean}true"/>
<model
jcr:primaryType="nt:unstructured"
name="cq:model"
propertyIndex="{Boolean}true"/>
<name
jcr:primaryType="nt:unstructured"
analyzed="{Boolean}true"
isRegexp="{Boolean}false"
name="jcr:content/data/master/name"
nodeScopeIndex="{Boolean}true"
ordered="{Boolean}true"
propertyIndex="{Boolean}true"
type="String"/>
</properties>
</nt:base>
</indexRules>
</foobarCFIndexFilter>
<cqProjectLucene/>
<ntFolderDamLucene/>
<acPrincipalName/>
<uuid/>
<damAssetLucene/>
<rep:policy/>
<cqPayloadPath/>
<nodetypeLucene/>
<nodetype/>
<ntBaseLucene/>
<reference/>
<principalName/>
<cqTagLucene/>
<lucene/>
<repTokenIndex/>
<externalId/>
<authorizableId/>
<cqPageLucene/>
</jcr:root>
Where in the synonyms.txt I had:
á, a
Á, A
and so on.
Also tried with a charFilter with Mapping equivalent chars.
I have made sure that my custom oak index is the one my query is using with Query Performance Diagnosis tool.
But nothing works, after reindex the query results are the same.
How to solve that?
I have the following XML file. I need to print a list of only selected nodes (Total) in ascending order. I tried to use sort function, but there were some mistakes I couldn't identify and it returned everything, including values of other nodes in the initial file.
XML input:
<?xml version="1.0" encoding="UTF-8"?>
<Invoice>
<From>
<Name>Lucy</Name>
<Country>UK</Country>
</From>
<To>
<Name>John</Name>
<Country>US</Country>
</To>
<Items>
<Position>
<Name>Table</Name>
<Total>1</Total>
</Position>
<Position>
<Name>Chair</Nr>
<Total>4</Total>
</Position>
<Position>
<Name>Cup</Name>
<Total>5</Total>
</Position>
<Position>
<Name>Box</Name>
<Total>4</Total>
</Position>
</Items>
</Invoice>
How could I get the required output using?
Any help is greatly appreciated! Thank you!
One obvious approach to generate the desired output from the given input would be using an xsl:for-each also making use of xsl:sort:
<xsl:template match="/Invoice">
<SortedTotalList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:for-each select="Positions/Position">
<xsl:sort select="Total"/>
<xsl:copy-of select="Total" />
</xsl:for-each>
</SortedTotalList>
</xsl:template>
Output is:
<?xml version="1.0"?>
<SortedTotalList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Total>1</Total>
<Total>4</Total>
<Total>4</Total>
<Total>5</Total>
</SortedTotalList>
I have 3 types of data
<results>
<place>
<key>place</key>
<value>1</value>
</place>
</results>
OR
<results>
<place>
<key>place</key> // notice the missing value
</place>
</results>
OR
<results>
</results>
So my sample data will be like
<event>
<results>
<place>
<key>place</key>
<value>1</value>
</place>
<some additional data here>
</results>
</event>
<event>
<results>
<place>
<key>place</key>
</place>
<some additional data here>
</results>
</event>
<event>
<results>
<some additional data here>
</results>
</event>
I need an XPath expression that can give me a default value when <value> of <place> is present, null or missing. <place> can be missing as well in some cases as mentioned in my third sample data.
Output that I expect here is 1, <default-value>, <default-value>.
XPATH 2.0 solution will work as well. I have tried scourging stackoverflow and google but couldnt find anything.
Use:
//results/concat(place/value, for $r in . return 'default-value'[not($r/place/value)])
XSLT - based verification:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:sequence select=
"//results/concat(place/value, for $r in . return 'default-value'[not($r/place/value)])"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided (and completed) XML document:
<t>
<event>
<results>
<place>
<key>place</key>
<value>1</value>
</place>
<x/>
</results>
</event>
<event>
<results>
<place>
<key>place</key>
</place>
<y/>
</results>
</event>
<event>
<results>
<z/>
</results>
</event>
</t>
the XPath expression is evaluated and its results are copied to the output:
1 default-value default-value
I did it finally after a lot of trial and error.
{xpath::/events/event/(results//(place|rank)/value/string(), '')[1]}
the trick was to go one level up i.e. <results> in my case and then use the (if value present, default-value) XPATH notation.
Earlier, I was trying this unsuccessfully.
{xpath::/events/event/results//((place|rank)/value/string(), '')[1]}
Given the following sample:
<?xml version="1.0" encoding="UTF-8"?>
<Patients>
<patientRole>
<id extension="996-756-495" root="2.16.840.1.113883.19.5"/>
<id extension="775-756-495" root="2.16.840.1.113883.14.6"/>
<patient>
<name>
<given>Henry</given>
<family>Levin</family>
</name>
<administrativeGenderCode code="M" codeSystem="2.16.840.1.113883.5.1"/>
<birthTime value="19320924"/>
</patient>
<providerOrganization>
<id root="2.16.840.1.113883.19.5"/>
<name>Good Health Clinic</name>
</providerOrganization>
<admissionTime value="2012030111:32"/>
</patientRole>
<patientRole>
<id extension="65" root="2.16.840.1.113883.3.933"/>
<patient>
<name>
<given>Paul</given>
<family>Pappel</family>
</name>
<administrativeGenderCode code="M" codeSystem="2.16.840.1.113883.5.1"/>
<birthTime value="19551217"/>
</patient>
<providerOrganization>
<id extension="84756-11241-283-OPTD-3322" root="1.2.3.4.5.6.1.8.9.0"/>
<name> Dr.med. Hans Topp-Glucklich</name>
</providerOrganization>
<admissionTime value="201201152200"/>
</patientRole>
<patientRole>
<id extension="800001" root="2.16.840.1.113883.19.5"/>
<patient>
<name>
<given>JEANNE</given>
<family>PETIT</family>
</name>
<administrativeGenderCode code="F" codeSystem="2.16.840.1.113883.5.1"/>
<birthTime value="19480105"/>
</patient>
<providerOrganization>
<id root="2.16.840.1.113883.19.5"/>
<name>Good Health Clinic</name>
</providerOrganization>
<admissionTime value="20120101T22:00"/>
</patientRole>
</Patients>
How would I write a X-Path expression for the following:
Family names for the male patients (gender code="M")
Any help is greatly appreciated I am new to XML/Xpath and i have tried multiple ways and its not generating what i need.
This should work:
/Patients/patientRole/patient[administrativeGenderCode/#code='M']/name/family
I have the following simple XML document:
<?xml version="1.0" encoding="UTF-8"?>
<cars>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>855</text>
</data>
</car>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>745</text>
</data>
</car>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>V70R</text>
</data>
</car>
</cars>
And the following XPath:
/cars/car/data[(#attrib='Model') and (text='855')]
This returns the following result:
<data attrib="Model"><text>855</text></data>
I want the XPath to return the whole <car> block for the match.
So return data would be like this:
<cars>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>855</text>
</data>
</car>
</cars>
How would I modify the XPath expression above to achieve this?
XPath returns whatever node you go up to - in your case you're going to data, so that's what you're getting back. If you want car instead, place your predicate after car.
/cars/car[data/#attrib='Model' and data/text='855']
Or, slightly shorter
/cars/car[data[#attrib='Model' and text='855']]
XQuery to produce the desired output:
<cars>
{/cars/car[data[#attrib='Model' and text='855']]}
</cars>
Here is a complete and likely one of the shortest possible XSLT solutions:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" />
<xsl:template match="/*">
<cars>
<xsl:copy-of select="car[data[#attrib='Model' and text='855']]"/>
</cars>
</xsl:template>
</xsl:stylesheet>
However, the following transformation, using the wellknown identity rule is both easier to write and provides maximum flexibility, extensibility and maintainability:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="car[not(data[#attrib='Model' and text='855'])]"/>
</xsl:stylesheet>
When either of these two transformations is applied on the provided XML document:
<cars>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>855</text>
</data>
</car>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>745</text>
</data>
</car>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>V70R</text>
</data>
</car>
</cars>
the wanted, correct result is produced:
<cars>
<car>
<data attrib="Make">
<text>Volvo</text>
</data>
<data attrib="Model">
<text>855</text>
</data>
</car>
</cars>
Explanation:
The first transformation generates the top element cars, then simply selects the wanted car element and copies it as the body of cars.
The second transformation is based on one of the most fundamental and powerful XSLT design patterns -- using and overriding the identity rule.
The identity template copies every matched node (for which it is selected to process) "as-is".
There is one template overriding the identity rule. This template matches any car for which it is not true that data[#attrib='Model' and text='855']. The body of the template is empty and this results in nothing from the matched car element being copied to the output -- in other words we can say that amy matching car element is "deleted".