问题
I'm trying to get the lN and the names of a person and the price of a car rental which is > 300
below is my XML example:
<rent number="101111">
<car>
<startDate>2018-02-08</startDate>
<endDate>2018-03-05</endDate>
<Location>Toranto</Location>
<carType>BMW</carType>
<transmissionType>Automatic</transmissionType>
</car>
<person>
<licenseNumber> 02389749372 </licenseNumber>
<name>Alexa Steve</name>
<dob>1999-03-01</dob>
<phone>
<type>Home</type>
<number>44 010 1111 4567</number>
</phone>
<email> Alexa@steve.ca</email>
</person>
<price>
<Rate>100.50</Rate>
</price>
</rent>
<rent number="103311">
<car>
<startDate>2018-07-01</startDate>
<endDate>2018-09-05</endDate>
<Location>ottawa</Location>
<carType>audi 8</carType>
<transmissionType>Automatic</transmissionType>
</vehicle>
<person>
<licenseNumber> 033329372 </licenseNumber>
<name>mike lornco</name>
<dob>1960-03-03</dob>
<phone>
<type>Home</type>
<number>44 010 1111 3333</number>
</phone>
<email> mikelornokorenco@gmail.com</email>
</person>
<price>
<Rate>300.50</Rate>
</price>
</rent>
what I am trying to do is to get the driving licence and age of a person who has a car rental which is >= 300
the separate query which works:
//price[Rate >= 300]
//person/name/licenseNumber
//person/name
//car/carType
回答1:
These expressions should work (result is a formatted string containing the required information) :
Xpath 1.0 :
concat(normalize-space(//Rate[.>=300]/preceding::licenseNumber[1]),"|",//Rate[.>=300]/preceding::name[1],"|",2020-substring(//Rate[.>=300]/preceding::dob[1],1,4))
Xpath 2.0 :
concat(replace(string-join(//Rate[.>=300]/preceding::person[1]/*[position()<3],"|"),"\W(\d+)\W(|.+)","$1$2"),"|",year-from-date(current-date())-year-from-date(//Rate[.>=300]/preceding::dob[1]))
Output (licence number, name, age) :
'033329372|mike lornco|60'
To test : https://www.freeformatter.com/xpath-tester.html
I suppose you have multiple items. You can iterate with :
concat(normalize-space((//Rate[.>=300]/preceding::licenseNumber[1])[x]),"|",(//Rate[.>=300]/preceding::name[1])[x],"|",2020-number(substring((//Rate[.>=300]/preceding::dob[x])[1],1,4)))
Where [x] starts from 1 to XXX.
EDIT : Your XML data contains errors. This is what I've used :
<data>
<rent number="101111">
<car>
<startDate>2018-02-08</startDate>
<endDate>2018-03-05</endDate>
<Location>Toranto</Location>
<carType>BMW</carType>
<transmissionType>Automatic</transmissionType>
</car>
<person>
<licenseNumber> 02389749372 </licenseNumber>
<name>Alexa Steve</name>
<dob>1999-03-01</dob>
<phone>
<type>Home</type>
<number>44 010 1111 4567</number>
</phone>
<email> Alexa@steve.ca</email>
</person>
<price>
<Rate>100.50</Rate>
</price>
</rent>
<rent number="103311">
<car>
<startDate>2018-07-01</startDate>
<endDate>2018-09-05</endDate>
<Location>ottawa</Location>
<carType>audi 8</carType>
<transmissionType>Automatic</transmissionType>
</car>
<person>
<licenseNumber> 033329372 </licenseNumber>
<name>mike lornco</name>
<dob>1960-03-03</dob>
<phone>
<type>Home</type>
<number>44 010 1111 3333</number>
</phone>
<email> mikelornokorenco@gmail.com</email>
</person>
<price>
<Rate>300.50</Rate>
</price>
</rent>
</data>
EDIT 2 : Explanation of the XPath 1.0 expression :
We use concat
to join the result of multiple operations (each one seperated with a ",") :
normalize-space(//Rate[.>=300]/preceding::licenseNumber[1])
: we get the licence number of a person who has a car rental which is >= 300 (XPath syntax).
We use normalize-space() to remove leading and closing whitespaces.
We put a "|" to separate the result from the next one.
//Rate[.>=300]/preceding::name[1]
: we get the name of a person who has a car rental which is >= 300 (XPath syntax).
2020-substring(//Rate[.>=300]/preceding::dob[1],1,4)
: we get the birthdate of a person who has a car rental which is >= 300. With this birthdate, we extract with susbtring() the year of birth ("1,4" means we want values from character 1 to character 4). Finally we substract this value from 2020 to get the age of the person.
EDIT 3 : XPath 1.0 to get the longest booking, see How do we get the Longest Booking in XPATH 1.0?
回答2:
I think this is what you are looking for, where you can get the age based on the DOB in the xml.
xs:integer((current-date()-xs:date(//price[Rate >= 300]/parent::rent/person/dob/text())) div xs:dayTimeDuration('P365D'))
Screenshot:
回答3:
I guess you're probably using XPath 1.0 (because people using later versions generally say so, and also because if you were using a later version, it would be easy).
what I am trying to do is to get the driving licence and the names & age of a person and the price of a car rental which is >= 300 alone [along?] with the car type
One difficulty here is that XPath 1.0 isn't strong on returning a composite result like this. What do you actually want to return? A set of nodes (if so, which nodes?). Perhaps a formatted string containing the required information? If you want to construct a composite result as XML, then you're out of luck, because XPath 1.0 can't construct nodes, it can only select them.
The other difficulty is (as per your question) doing the join. XPath 1.0 is not "relationally complete" in Codd's terminology, that is, it doesn't have equivalent power to first-order predicate calculus, which means that not all joins are expressible.
My advice would therefore be that XPath 1.0 is the wrong tool for the job. You should be looking at XQuery, XPath 2.0, or XSLT. Do you have technology constraints that prevent you using such tools?
来源:https://stackoverflow.com/questions/61242076/how-do-we-join-in-xpath-using-version-1-0