Nesting in XPATH - count

I have the following XML data for which I would like create an xpath statement which i think might contain nested count()
Here is the XML data for 5 CD Rentals
<?xml version="1.0"?>
<DataBase>
<!-- CD Rental 1 -->
<Rental>
<cd>
<title>title1</title>
</cd>
<person uniqueID = "1">
<name>name1</name>
</person>
</Rental>
<!-- CD Rental 2 -->
<Rental>
<cd>
<title>title2</title>
</cd>
<person uniqueID = "2">
<name>name2</name>
</person>
</Rental>
<!-- CD Rental 3 -->
<Rental>
<cd>
<title>title3</title>
</cd>
<person uniqueID = "1">
<name>name1</name>
</person>
</Rental>
<!-- CD Rental 4 -->
<Rental>
<cd>
<title>title4</title>
</cd>
<person uniqueID = "3">
<name>name3</name>
</person>
</Rental>
<!-- CD Rental 5 -->
<Rental>
<cd>
<title>title5</title>
</cd>
<person uniqueID = "2">
<name>name2</name>
</person>
</Rental>
</DataBase>
The xpath I had in mind was
Count the number of persons who rented multiple CD's
In the above XML data, the person with name as name1 and the person with name as name2 rented 2 CD's while name3 only rented 1 CD. So the answer I am expecting is 2. What could be a possible xpath for this?

One possible XPath expression would be:
count(//name[.=preceding::name][not(. = following::name)])
xpathtester demo
Brief explanation about the expression inside count():
//name[.=preceding::name]: find all elements name which have preceding element name with the same value, in other words name with duplicate
[not(. = following::name)]: further filter name elements found by the previous piece of XPath to return only the last of each duplicated name (distinct in Xpath?)

Related

Working with XML file with tags with different ids attributes

This is my xml file:
<Games>
<Game id = 1>
<Q>1</Q>
<Q>Rick</Q>
<Q>623.3</Q>
<Q>1/1/2012</Q>
<Q>IT</Q>
</Game>
<Game id = 2>
<Q>2</Q>
<Q>Dan</Q>
<Q>515.2</Q>
<Q>9/23/2013</Q>
<Q>Operations</Q>
</Game>
<Game id = 3>
<Q>3</Q>
<Q>Michelle</Q>
<Q>611</Q>
<Q>11/15/2014</Q>
<Q>IT</Q>
</Game>
<Game id = 4>
<Q>4</Q>
<Q>Ryan</Q>
<Q>729</Q>
<Q>5/11/2014</Q>
<Q>HR</Q>
</Game>
<Game id = 5>
<Q>5</Q>
<Q>Gary</Q>
<Q>843.25</Q>
<Q>3/27/2015</Q>
<Q>Finance</Q>
</Game>
<Game id = 6>
<Q>6</Q>
<Q>Nina</Q>
<Q>578</Q>
<Q>5/21/2013</Q>
<Q>IT</Q>
</Game>
</Games>
The tags Gamehave ids and other attributes. Using game <- xml_find_all(xml_file, xpath = "//Games/Game") and then game_attr_dataframe <- xml_attrs(game_node) %>% as.data.frame()
I am able to extract all the Game Tags and organize them in a dataframe.
The problem is when I do the same to extract the children Game tag Q.
I do this: q <- xml_find_all(xml_file, xpath = "//Games/Game/Q") and then q_attr <- xml_attrs(q_node)
The result is a huge "xml_nodeset" vector and I lost which Q tag belongs to which Game with its respectively id.
If somehow I can identify from what id attribute Game tag the q_attr elemnts came from my proble would be solved.
Am I clear? Please let me kno.
Thanks
with library XML this should work (but be prepared for errors when attribute values are not enclosed with ")
library(XML)
library(methods)
xmlToDataFrame('your-xml-file.xml')
## Q NA NA NA NA
## 1 1 Rick 623.3 1/1/2012 IT
## 2 2 Dan 515.2 9/23/2013 Operations
## ...
## <Game id = 1> throws an error
## <Game id = "1"> works

How to insert xml string into Oracle database in a stored procedure?

My XML data is:
<NewDataSet>
<AotReversefeedback>
<Refid>N161144</Refid>
<DPID />
<TrdAccOpenId>92021144 </TrdAccOpenId>
<TrdAccOpenDate>May 7 2018 12:00AM </TrdAccOpenDate>
<EntryDate>25/03/2018</EntryDate>
<ITicketStatus>POA</ITicketStatus>
<LastupdatedDate>07/05/2018</LastupdatedDate>
<Status>ACTIVE</Status>
</AotReversefeedback>
<AotReversefeedback>
<Refid>N202240</Refid>
<DPID />
<TrdAccOpenId>83082240 </TrdAccOpenId>
<TrdAccOpenDate>May 7 2018 12:00AM </TrdAccOpenDate>
<EntryDate>03/05/2018</EntryDate>
<ITicketStatus>KRA</ITicketStatus>
<LastupdatedDate>07/05/2018</LastupdatedDate>
<Status>ACTIVE</Status>
</AotReversefeedback>
</NewDataSet>
and my table structure is
create table LMSDATA
(
refid nvarchar2(20),
DPID NVARCHAR2(20),
trdaccopenid number(9),
trdaccopendate nvarchar2(20),
entrydate date,
iticketstatus nvarchar2(20),
lastupdateddate date,
status nvarchar2(20)
);
The stored procedure will get input string which has xml data. What method can be used to insert XML data into table?
Would be this one:
WITH t AS
(SELECT XMLTYPE(
'<NewDataSet>
<AotReversefeedback>
<Refid>N161144</Refid>
<DPID />
<TrdAccOpenId>92021144 </TrdAccOpenId>
<TrdAccOpenDate>May 7 2018 12:00AM </TrdAccOpenDate>
<EntryDate>25/03/2018</EntryDate>
<ITicketStatus>POA</ITicketStatus>
<LastupdatedDate>07/05/2018</LastupdatedDate>
<Status>ACTIVE</Status>
</AotReversefeedback>
<AotReversefeedback>
<Refid>N202240</Refid>
<DPID />
<TrdAccOpenId>83082240 </TrdAccOpenId>
<TrdAccOpenDate>May 7 2018 12:00AM </TrdAccOpenDate>
<EntryDate>03/05/2018</EntryDate>
<ITicketStatus>KRA</ITicketStatus>
<LastupdatedDate>07/05/2018</LastupdatedDate>
<Status>ACTIVE</Status>
</AotReversefeedback>
</NewDataSet>') AS XML_DATA
FROM dual)
SELECT
refid,
DPID,
trdaccopenid,
trdaccopendate,
TO_DATE(entrydate_str, 'dd/mm/yyyy') AS entrydate,
iticketstatus,
TO_DATE(LastupdatedDate_str, 'dd/mm/yyyy') AS LastupdatedDate,
status
FROM t
CROSS JOIN XMLTABLE('/NewDataSet/AotReversefeedback' PASSING XML_DATA COLUMNS
refid NVARCHAR2(20) PATH 'Refid',
DPID NVARCHAR2(20) PATH 'DPID',
trdaccopenid NUMBER(9) PATH 'TrdAccOpenId',
trdaccopendate NVARCHAR2(20) PATH 'TrdAccOpenDate',
entrydate_str VARCHAR2(15) PATH 'EntryDate',
iticketstatus NVARCHAR2(20) PATH 'ITicketStatus',
lastupdateddate_str VARCHAR2(15) PATH 'LastupdatedDate',
status NVARCHAR2(20) PATH 'Status'
) x;
Results:
REFID DPID TRDACCOPENID TRDACCOPENDATE ENTRYDATE ITICKETSTATUS LASTUPDATEDDATE STATUS
N161144 92021144 May 7 2018 12:00AM 25.03.2018 POA 07.05.2018 ACTIVE
N202240 83082240 May 7 2018 12:00AM 03.05.2018 KRA 07.05.2018 ACTIVE
ExtractValue will also works but the function is deprecated.

Grouping in XQuery FLWOR to generate a space-separated list of values for each key

I have a XML with 5 articles, each one of them:
<root>
<article>
<c0>
<number>
</number>
<price>
</price>
</c0>
<c1>
<name> NewArtc1
</name>
<nameUs>TheBest
</nameUs>
</c1>
<c2>
<name> c2_1
</name>
<nameUs>NotTheBest
</nameUs>
</c2>
<c2>
<name> c2_2
</name>
<nameUs>TheBest
</nameUs>
</c2>
<c2>
<name> c2_3
</name>
<nameUs>NotTheBest
</nameUs>
</c2>
<c2>
<name> c2_4
</name>
<nameUs>TheBest
</nameUs>
</c2>
<c2>
<name> c2_5
</name>
<nameUs>NotTheBest
</nameUs>
</c2>
</article>
<article> ...
</root>
Each item has several characteristics (c0, c1, c2, etc.). I need, using XQuery (FLWOR), to return the names of c1. followed by the names of c2 whose text of the nameUs node matches that of the nameUs node c1 (there are 5 c2 for each article) The output format should be, for each article:
<c1>
<name>NewArtc1</name>
<c2s>c2_2 c2_4</c2s>
</c1>
<c1>
<name>NewArtc2</name>
<c2s>c2_3 c2_5</c2s>
</c1>
Please help me :/ I've done this, but it returns pairs, not the output format I need:
for $a in doc("articles.xml")//article, $i in 1 to 5
let $b:=$a/c1/nameUs
let $c:=$a/c2[$i]/nameUs
where $b/text() and $b/text()=$c/text()
return <c1>{$b/name}<c2>{$c/name/text()}</c2></c1>
Maybe try something like...
for $arcticle in /root/article
let $name := $arcticle/c1/name/normalize-space()
let $nameUs := $arcticle/c1/nameUs/normalize-space()
return
<c1>
<name>{$name}</name>
<c2s>{$arcticle/c2[normalize-space(nameUs)=$nameUs]/name/normalize-space()}</c2s>
</c1>

range index on mixed content node in exist db

My xml file is with the structure
<root>
<compound>abc<parts>a b c</parts></compound>
<compound>xyz<parts>x y z</parts></compound>
</root>
I have created a range index on
<range>
<create qname="compound" type="xs:string"/>
</range>
I expected the index terms are abca b c and xyzx y z but I found abc and xyz under index link in monitoring and profiling window. And also the search string
//compound[.="abca b c"] giving 0 results.
Can any one help in creating index on the whole contents of compound like on abca b c, xyz x y z so on..
Thanks
sony
In xquery, you have to use data() function in order to return all of the descendant or the sub-element values.
So, to test if the values of the compound element can be returned you can use the following:
//compound/data()[.="abca b c"]
nested="yes" attribute solved the problem.
I have changed the range index to
<range>
<create qname="compound" type="xs:string" nested="yes" />
</range>

Xquery with multiple elements

I have a XML named 'fruits.XML' as follows
<fruits>
<fruitbasket>
<id>123 </id>
<apple>Apple 1 </apple>
<apple>Apple 2 </apple>
</fruitbasket>
<fruitbasket>
<id> 1 </id>
<apple>Apple 2 </apple>
<apple>Apple 3 </apple>
</fruitbasket>
</fruits>
How to find the baskets with Apple 2 in Xquery? I get a multiple element error when i use the matches in the Query.
try this:
for $element in doc('fruits.xml')//fruitbasket
where $element/apple = 'Apple 2 '
return $element

Resources