XML xpath, get the child of root element - java

Below XML is provided for example.
<?xml version="1.0" encoding="utf-8"?>
<store d:mi="22">
<book price="12.99" d:price="Number" d:mi="4">
<title d:constr="String" d:mi="1">Sword of Honour</title>
<category d:constr="String" d:mi="2">fiction</category>
<author d:constr="String" d:mi="3">Evelyn Waugh</author>
</book>
<book price="8.99" d:price="Number" d:mi="9">
<sublist>
<title d:constr="String" d:mi="5">Moby Dick</title>
<category d:constr="String" d:mi="6">fiction</category>
<author d:constr="String" d:mi="7">Herman Melville</author>
<isbn d:constr="String" d:mi="8">0-553-21311-3</isbn>
</sublist>
</book>
<Note price="8.95" d:price="Number" d:mi="13">
<title d:constr="String" d:mi="10">50</title>
<category d:constr="String" d:mi="11">reference</category>
<author d:constr="String" d:mi="12">Nigel Rees</author>
</Note>
<Note price="22.99" d:price="Number" d:mi="18">
<title d:constr="String" d:mi="14">The Lord of the Rings</title>
<category d:constr="String" d:mi="15">fiction</category>
<author d:constr="String" d:mi="16">J. R. R. Tolkien</author>
<isbn d:constr="String" d:mi="17">0-395-19395-8</isbn>
</Note>
</store>
Using the below Xpath I'm able to get the store element.
String name = "String";
String xpath = "//title[#d:constr='" + name + "']/parent::store";
But we need to get book(Anything may come which we Don't know) which is the child of store(constant word). Is it possible to do that?

Try to use below expression to match parent of required title ignoring node name:
String name = "String";
String xpath = "//title[#d:constr='" + name + "']/parent::*";
Also note that store is not parent of title, you should use "//title/ancestor::store" instead of "//title/parent::store"
If you simply want to get child of store:
//store/child::*
First child:
//store/child::*[1]

Related

How to capture XML message from a request sent from SOAPui to Wiremock Server to compare against an XSD file

I need to capture an XML message that is sent as part of a request from SOAPui to Wiremock Server. Upon capturing this file, I would then need to compare it against an XSD file. The hard bit is capturing the XML file, I'm not sure what methods wiremock server has that would enable this.
For example, this is the XML message I want to capture in my java application:
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="web">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
<book category="web">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
What would I need to capture this?

How to get xml attribute value containing multiple colons in a single tag i.e. namespaces?

Here is my XML:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="XYZ" xmlns:d="http://schemas/services" xmlns:m="http://schemas/metadata" xmlns="http://www.abc.pqr/Atom">
<title type="text">Title</title>
<id>Id</id>
<updated>2018-02-08</updated>
<link rel="self" title="titl" href="title" />
<entry m:etag="W/"25"">
<id>id1</id>
<title type="text">title_text</title>
<updated>2018-02-08</updated>
<author>
<name />
</author>
<link m:etag=""{acx},25"" rel="edit-media" title="title_value" />
<link rel="edit" title="title" />
<link rel="http://az.com/CreatedBy" type="application/atom+xml;type=entry" title="CreatedBy" href="title/CreatedBy" />
<link rel="http://az.com/ModifiedBy" type="application/atom+xml;type=entry" title="ModifiedBy" href="title/ModifiedBy" />
<link rel="http://az.com/CheckedOutTo" type="application/atom+xml;type=entry" title="CheckedOutTo" href="title/CheckedOutTo" />
<category term="xyz" scheme="xyz" />
<content type="application/octetstream" src="http://collb.xlsm" />
<m:properties xmlns:m="http://xyz/metadata" xmlns:d="wsx/dataservices">
<d:ContentTypeID>contentId</d:ContentTypeID>
<d:Dept>21</d:Dept>
<d:Class>0</d:Class>
<d:Id m:type="Edm.Int32">2121</d:Id>
</m:properties>
</entry>
<link rel="next" href="http://tyu.com" />
</feed>
I want to read values corresponding to <d:Id m:type> and <entry m:etag> i.e. output should be 2121 and 25.
How should I read these.
P.S: I have gone through similar questions asked on stackoverflow, but nothing worked for me.
Part of my code:
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilder = builderFactory.newDocumentBuilder();
Document doc = documentBuilder.parse(connection.getInputStream());
Element element = doc.getDocumentElement();
element.getAttributeNodeNS("http://schemas/metadata", "type");
You haven't said which of the vast choice of Java APIs you are using. I guess that probably means you're using DOM. I don't know why anyone still uses DOM when there are much better alternatives available, but they do.
Whichever API you are using, you'll find that there's probably a method something like
element.getAttributeValue(namespace, localname)
To read the m:type attribute, you would use
element.getAttributeValue("http://schemas/metadata", "type")

Xpath with Default Namespace

I am trying to get all values of a certain XML element. However, the namespace is not defined. I've tried using the local-name() function but am not having any luck.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="https://www.website.com" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<id>A</id>
<title type="text"></title>
<updated>2015-07-21T02:40:30Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Application" href="A(1347)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/b" type="application/atom+xml;type=feed" title="B" href="A(1347)/B" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/C" type="application/atom+xml;type=feed" title="C" href="A(1347)/C" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/D" type="application/atom+xml;type=entry" title="D" href="A(1347)/D" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/E" type="application/atom+xml;type=feed" title="E" href="A(1347)/E">
<m:inline>
<feed>
<title type="text">E</title>
<id>1347</id>
<updated>2015-07-21T02:40:30Z</updated>
<link rel="self" title="E" href="A(1347)/E" />
<entry>
<id>www.website.com/</id>
<title type="text"></title>
<updated>2015-07-21T02:40:30Z</updated>
<author>
<name />
</author>
<link rel="edit" title="E" href="E(4294)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/A" type="application/atom+xml;type=entry" title="Application" href="E(4294)/A" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/D" type="application/atom+xml;type=entry" title="D" href="E(4294)/D" />
<category term="APIModel.FileBaseDocuments" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:ID m:type="Edm.Int32">4294</d:ID>
<d:Type>123</d:Type>
</m:properties>
</content>
</entry>
<entry>
<id>www.website.com</id>
<title type="text"></title>
<updated>2015-07-21T02:40:30Z</updated>
<author>
<name />
</author>
<link rel="edit" title="E" href="E(4295)" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/A" type="application/atom+xml;type=entry" title="A" href="E(4295)/A" />
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/D" type="application/atom+xml;type=entry" title="D" href="E(4295)/D" />
<category term="APIModel.FileBaseDocuments" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:ID m:type="Edm.Int32">4295</d:ID>
<d:Type>456</d:Type>
</m:properties>
</content>
</entry>
</feed>
</m:inline>
</link>
</entry>
I want to retrieve all values inside of "m:properties/d:ID m:type="Edm.Int32" (in this case 4294) but I am getting no luck. So for one file, there would be one "feed" tag filled with multiple "entry" tags. Inside these tags there would be one "m:properties/d:ID m:type="Edm.Int32" which I need to retrieve. Any suggestion on what the correct xPath would be for this situation?
Instead of resorting to namespace agnostic xml by using local-name(), why not register a namespace for the default namespace, e.g. x prefix for xmlns:x="http://www.w3.org/2005/Atom", and then your Xpath would be something like:
//x:feed/x:entry/x:content/m:properties/d:ID[#m:type='Edm.Int32']
The local-name() approach is more verbose:
//*[local-name()='feed']/*[local-name()='entry']/*[local-name()='content']
/*[local-name()='properties']/*[local-name()='ID' and #m:type='Edm.Int32']
Example of both approaches here
Use the #exclude-result-prefixes attribute to filter out the extraneous namespaces in your output. You don't need to declare the http://www.w3.org/2005/Atom in your transform, unless you need it for other purposes, but even so, it is probably a good thing.
Just match on expression m:properties/d:ID[#m:type='Edm.Int32'] to get your required data.
For example, this transform, when applied to your given input document ....
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns:atom="http://www.w3.org/2005/Atom"
version="2.0"
exclude-result-prefixes="xsl d m atom">
<xsl:output encoding="utf-8" omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/">
<Edm.Int32s>
<xsl:apply-templates />
</Edm.Int32s>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="text()" />
<xsl:template match="m:properties/d:ID[#m:type='Edm.Int32']">
<value><xsl:value-of select="text()" /></value>
</xsl:template>
</xsl:stylesheet>
... yields output ....
<edm.int32s>
<value>4294</value>
<value>4295</value>
</edm.int32s>
Note
I have assumed from your question tags that you want an XSLT transform. If you just wanted a simple XPath expression to apply directly to the document, you could use ...
//m:properties/d:ID[#m:type='Edm.Int32']/text()
(passing, of course, the namespace declarations for m and d).

Java XPathExpression for Child Element Using Parent Element As XPath Parameter

For the following xml:
<books>
<book>
<author>Peter</author>
<title>Tales from Somewhere</title>
<data>
<version>1</version>
</data>
</book>
<book>
<author>Paul</author>
<title>Tales from Nowhere</title>
<data>
<version>2</version>
</data>
</book>
</books>
How can I get the <version> value of the book author 'Paul' above, using this type of notation for building a Java XPathExpression:
//*[local-name()='books']/*
?
I used the following question as a reference:
Get first child node in XSLT using local-name()
Thanks!
This XPath will get the version of a book where there is at an author element with the value "Paul":
//book[author="Paul"]/data/version
When run against this XML:
<books>
<book>
<author>Peter</author>
<title>Tales from Somewhere</title>
<data>
<version>1</version>
</data>
</book>
<book>
<author>Paul</author>
<title>Tales from Nowhere</title>
<data>
<version>2</version>
</data>
</book>
<book>
<author>Peter</author>
<author>Paul</author>
<title>How to write a book with a friend</title>
<data>
<version>7</version>
</data>
</book>
</books>
You get this result:
<version>1</version>
<version>7</version>

xpath based on condition in java

I have an xml of the following structure:
<Root>
<Sample>
<Materil material_class="book" />
<Book Name="harry" Price="8" />
<Book Name="small things" Price="9" />
<Book Name="snow" Price="10" />
</Sample>
<Commodity>
<Sample>
<Materil material_class="sub" />
<Book Name="sherin" Price="8" />
<Book Name="bigthings" Price="9" />
<Book Name="leopard" Price="10" />
</Sample>
<Commodity>
<Sample>
<Materil material_class="sub" />
<Book Name="azxcv" Price="86" />
<Book Name="ddddd" Price="79" />
<Book Name="qwert" Price="810" />
</Sample>
</Commodity>
<Commodity>
<Sample>
<Materil material_class="subtwo" />
<Book Name="ratnam" Price="86" />
<Book Name="shantharam" Price="99" />
<Book Name="da vinci" Price="10" />
</Sample>
</Commodity>
</Commodity>
</Root>
Is there a way to iterate this xml based on condition like,if the material_class = "sub", iterate the Book tag below that and store the #Name and #Price . If the material_class = "book", iterate the Book tag below that. Also i want to get the length of number of /Root/Commodity/Commodity tags (in this case , it is two). Any help is appreciated. I am new to XPath.
To get the Book #Name and #Price for #material_class='sub' or #material_class='book', use this XPATH
/Root[descendant-or-self::Sample or Sample[descendant-or-self::*]]//*[Materil[#material_class='sub' or #material_class='book']]/Book
OR
//Sample[Materil[#material_class='book' or #material_class='sub']]/Book
After loading this XPATH, to print the Name use #Name and Price use #Price
To get the length of number of /Root/Commodity/Commodity tags, XPATH is
/Root/Commodity/Commodity
OR
//Commodity/Commodity
JAVA:
NodeList node = (NodeList) xpath.evaluate("/Root/Commodity/Commodity", xml, XPathConstants.NODESET);
count = node.getLength(); // OUTPUTS: 2
For your information, actually rendering XML through XSLT is much better performance and easier to implement.
<xsl:apply-templates select="//Sample[Materil[#material_class='sub']]/Book"/>
<xsl:apply-templates select="//Sample[Materil[#material_class='book']]/Book"/>
I do not have access to an XSL editor right now, so have not tested the above, but it will give you an idea. Select the Book, and constrain the Materil with the condition you want.

Categories