Convert one child element of an XML structure into a Java object - java

I have an XML structure of a message received from an XMPP subscription (below). I only care about the "user" part of this message and would like to convert this into an equivalent "User" object in Java so that I can use it to perform other processing. Is there a way to achieve this in Java?
The only way I know I can do it is to use Jackson annotations (e.g #JsonProperty) and create the equivalent objects for all the parent elements - event, notification, update, data etc - but I don't really care about them so seems like a waste.
Not sure how I can just convert the "user" part to an object and forget about the rest?
<event xmlns='http://jabber.org/protocol/pubsub#event'>
<notification xmlns='http://jabber.org/protocol/pubsub'>
<Update>
<data>
<user>
<dialogs>/finesse/api/User/1234/Dialogs</dialogs>
<extension></extension>
<firstName>1234</firstName>
<lastName>1234</lastName>
<loginId>1234</loginId>
<loginName>1234</loginName>
<roles>
<role>Agent</role>
</roles>
<state>LOGOUT</state>
<stateChangeTime>2015-03-11T14:25:42Z</stateChangeTime>
<teamId>1</teamId>
<teamName>Default</teamName>
<uri>/finesse/api/User/1234</uri>
</user>
</data>
</Update>
</notification>
</event>

It's a little bit ugly and not optimal for huge xml data, but you could extract user part from xml using for example dom4j and than use Jackson to parse "only user xml" part.
Document doc = new SAXReader().read(...);
Node user = doc.getRootElement()
.element("notification")
.element("Update")
.element("data")
.element("user");
String onlyUserXml = user.asXML();

Related

Having namespace prefix in Jackson response

I am not a expert on Java but looking for help on issue we are seeing. With our java Jackson response , we are trying to build a XML based response but response is coming without a namespace prefix like below
Kindly help
<EmployeeResponse **xmlns**="http://test.service.net/com/v1">
<Reference>SequenceTime="2019-03-07 12.15.01.970236"</Reference>
<Details>
<Name>
<FirstName>Alex</FirstName>
</Name>
</Details>
</EmployeeResponse>
However we would like to have the response defined as a space prefix like below where v1 would denote a namespace type and same should be mapped to all child elemetns.
<v1:EmployeeResponse xmlns:v1="http://test.service.net/com/v1">
<v1:Reference>SequenceTime="2019-03-07 12.15.01.970236"</v1:Reference>
<v1:Details>
<v1:Name>
<v1:FirstName>Alex</v1:FirstName>
</v1:Name>
</v1:Details>
</v1:EmployeeResponse>

Generating xsd and Java classes for varying xml child tag - JAXB

I'm wondering if we could generate xsd and corresponding java classes for varying child xml tags. I'm pretty new to xml parsing.
Case : 1
<?xml version="1.0"?>
<SSNExportDocument xmlns="urn:com:ssn:schema:export:SSNExportFormat.xsd" Version="0.1" DocumentID="8b6fdfce-9f5f-4110-b6da-c5650f0851c2-1" ExportID="8b6fdfce-9f5f-4110-b6da-c5650f0851c2" JobID="464" RunID="3726980" CreationTime="2019-06-01T20:20:00.417-04:00" StartTime="2019-06-01T14:20:00.000-04:00" EndTime="2019-06-01T20:20:00.000-04:00">
<MeterData MeterName="CBRE-11459398" UtilDeviceID="11459398" MacID="anonymized">
<RegisterData StartTime="2019-06-01T14:00:00.000-04:00" EndTime="2019-06-01T14:00:00.000-04:00" NumberReads="1">
<RegisterRead ReadTime="2019-06-01T14:00:00.000-04:00" GatewayCollectedTime="2019-06-01T19:40:03.116-04:00" RegisterReadSource="REG_SRC_TYPE_EO_CURR_READ" Season="-1">
<Tier Number="0">
<Register Number="1" Summation="9981.2000" SummationUOM="GAL"/>
</Tier>
</RegisterRead>
</RegisterData>
</MeterData>
<MeterData MeterName="CBRE-11460365" UtilDeviceID="11460365" MacID="anonymized">
<RegisterData StartTime="2019-06-01T14:00:00.000-04:00" EndTime="2019-06-01T14:00:00.000-04:00" NumberReads="1">
<RegisterRead ReadTime="2019-06-01T14:00:00.000-04:00" GatewayCollectedTime="2019-06-01T19:40:03.113-04:00" RegisterReadSource="REG_SRC_TYPE_EO_CURR_READ" Season="-1">
<Tier Number="0">
<Register Number="1" Summation="142104.1000" SummationUOM="GAL"/>
</Tier>
</RegisterRead>
</RegisterData>
</MeterData>
</SSNExportDocument>
Case: 2
<?xml version="1.0"?>
<SSNExportDocument xmlns="urn:com:ssn:schema:export:SSNExportFormat.xsd" Version="0.1" DocumentID="7b9d9a38-7739-4c67-9fb3-08ff1826d966-2" ExportID="7b9d9a38-7739-4c67-9fb3-08ff1826d966" JobID="465" RunID="2983700" CreationTime="
:2018-12-19T20:20:01.218-05:00" StartTime="2018-12-19T14:20:00.000-05:00" EndTime="2018-12-19T20:20:00.000-05:00">
<MeterData MeterName="CBRE-11460650" UtilDeviceID="11460650" MacID="00:11:01:ff:fe:00:db:ff">
<IntervalReadData IntervalLength="60" StartTime="2018-12-19T07:00:00.000-05:00" EndTime="2018-12-19T19:00:00.000-05:00" NumberIntervals="12">
<Interval EndTime="2018-12-19T08:00:00.000-05:00" GatewayCollectedTime="2018-12-19T19:40:03.052-05:00" BlockSequenceNumber="0" IntervalSequenceNumber="6636688262981226347">
<Reading Channel="1" RawValue="0.0" Value="0" UOM="GAL" BlockEndValue="78582.3000"/>
</Interval>
<Interval EndTime="2018-12-19T09:00:00.000-05:00" GatewayCollectedTime="2018-12-19T19:40:03.052-05:00" BlockSequenceNumber="0" IntervalSequenceNumber="6636703724863491951">
<Reading Channel="1" RawValue="0.0" Value="0" UOM="GAL" BlockEndValue="78582.3000"/>
</Interval>
</IntervalReadData
</MeterData>
</SSNExportDocument>
In above cases, as you can see contents of MeterData tag are different but MeterData tag remains same.
XML documents are often described as "semi-structured", but in truth, they are on a spectrum from highly-structured to highly-unstructured. Conventional programming languages like Java are best at dealing with highly-structured data, and as a result, data binding technologies like JAXB work best at this end of the spectrum. The more you move to highly-unstructured (e.g. HTML) the more difficult JAXB becomes; at that end of the spectrum you should either be using generic tree models like DOM, XOM, or JDOM, or specialist XML processing languages like XSLT and XQuery. The example you've show is in the middle of the spectrum, where you are starting to move out of the JAXB comfort-zone, but where it's still just about viable.
There's another dimension here which is the stability of the structure over time. The more often the schema changes, the more you're moving out of JAXB's comfort zone.

How to store XQuery results as new document in BaseX

I am very new to XML document database technologies, Xquery/Xpath and so on. So this is probably a very newbie question.
Scenario: A number of XML documents as the input, want to run some number of transformations can be run on these XML documents (using XQuery). I'd like to store these results. Into the same XML data store as the input.
So far I am experimenting with using the BaseX document database to store and processes these XML documents, and so far its been very easy to work with, I am impressed.
Ideally I'd like to interface with BaseX using the XQJ API (http://xqj.net/basex/) as my reasoning would be that XQJ would keep the implementation of application code independent of BaseX as can be. The secondary option would write my java code directly to the BaseX API.
The Problem: I am having a hard time figuring out how to store the results from an XQuery as a new "document" in the database. Perhaps this is more of a conceptual lack of understanding with XQuery (or XQuery Update) itself than any difficulty with the BaseX/XQJ API.
In this simple example if I have a query like this, it returns some XML output with in a format that I want for my new document
let $items := //firstName
return <results>
{ for $item in $items
return <result> {$item} </result>
}
</results>
Gives
<results>
<result>
<firstName>Bob</firstName>
</result>
<result>
<firstName>Joe</firstName>
</result>
<result>
<firstName>Tom</firstName>
</result>
</results>
I want to store this new <result> document back into the database, for use in later querying/transformations/etc. In SQL this makes sense to me. I would do CREATE TABLE <name> SELECT <query> or INSERT INTO, etc. But I am unclear what the equivalent is in XQuery. I think the XQuery Update functionality is what I need here, but I'm having trouble finding concrete examples.
This is further complicated when dealing with XQJ
XQResultSequence rs = xqe.executeQuery("//firstName");
// what do i do with it now??
Is there a way to persist this XQResultSequence back INTO the database using BaseX? Or even better, can I run additional XQueries directly on the XQResultSequence?
Thanks for the help!
BaseX implements XQuery Update Facility, so you should be able to use fn:put:
let $items := //firstName
return fn:put(
<results>{
for $item in $items
return <result> {$item} </result>
}</results>,
"/results/result-new.xml")
If you are running simple ad-hoc queries like above, it should be fairly straightforward. I'm not very familiar with XQJ, but if you want to run queries in a sequence, I suspect there is a way to pass those XQResultSequence variables back to a new query, in which you would likely accept it by declaring a variable as external in the following query:
declare variable $previous-result as item()* external;

How can I parse CDATA?

How can I find and iterate through all the nodes present under CDATA and those nodes are started by (<) and closed by (>)?
Also, how should I iterate over all the child nodes and get the values like in below child node? I want to retrieve the value.
Input XML
<SOURCE TransactionId="1" ProviderName="ABCDD"><RESPONSE><![CDATA[<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><NetworkResponse xmlns="http://www.example.com/"><NetworkResult><Network offering_id="13" transaction_id="2" submission_id="3" timestamp="20140828 16010683 GMT" customer_id="NETTest">
<Network_List>
<Network_Info att0="Y" att1="N" att2="N" att3="Y" att4="Y">
<SIM_DATA>
<SIM><![CDATA[1100040101]]></SIM>
</SIM_DATA>
<NetworkResponseInfo k_status="C">
<KEY1>269</KEY1>
<PARENTNODE>
<CHILDNODE1>
<KEY2>XXXXXXX</KEY2>
<KEY3>YYYYYYY</KEY3>
</CHILDNODE1>
<CHILDNODE2>
<KEY4>N</KEY4>
<KEY5>I</KEY5>
</CHILDNODE2>
<CHILDNODE3>
<KEY6>1</KEY6>
<KEY7>3</KEY7>
</CHILDNODE3>
</PARENTNODE>
<KEY8><![CDATA[some image not visible]]></KEY8>
<KEY9>N</KEY9>
<KEY10>15</KEY10>
</NetworkResponseInfo>
</Network_Info>
</Network_List>
<response_message_list transaction_status_code="000" transaction_status_text="Successful"/>
</Network></NetworkResult></NetworkResponse></soap:Body></soap:Envelope>]]></RESPONSE></SOURCE>
Output XML
<ns3:NetworkResponse>
<Networks_OF_List>
<NetCharSeq>
<Nrep>
<type>Some Image</type>
<data> Data Coming from KEY8 CDATA section</data>
</Nrep>
<Nrep>
<type>ANYTHING</type>
<data>VALUE INSIDE SIM CDATA</data>
</Nrep>
<NetDetail>
<MYKEY1>Value present inside KEY4</MYKEY1>
<MYKEY2>Value present inside KEY5</MYKEY2>
</NetDetail>
<SystemID>Value of KEY2</SystemID>
<SystemPath>Valuelue of KEY3</SystemPath>
</NetCharSeq>
</Networks_OF_List>
</ns3:NetworkResponse>
(Welcome at SO. Please note that you are downvoted by some users because you do not show what you have done so far. Have a look at the How To Ask section to learn how to ask questions that actually can be answered and are considered proper questions in the SO format.)
If you can use XSLT 3.0, you can consider using the new fn:parse-xml function, which will take a document-as-a-string.
However, your CDATA-section contains itself escaped data, which means that, after you apply fn:parse-xml, you will have to do it once again for the text node that is the child of NetworkResult.
A better solution is often to fix this at the source and creating an XML format that allows other XML in certain elements (you can allow this with a proper XSD). It will save you a lot of trouble and at least you XML can then be pre-validated.
If you are stuck with XSLT 2.0 or 1.0, you can use disable-output-escaping (google it, there is a lot of info around on how to use it), but you will have to re-process your output once more because of the double-escape that is used. You may want to consider an XProc pipeline to ease the process.
You wrote: Also, how should I iterate over all the child nodes and get the values like in below child node
That is what XSLT is all about, please read this XSLT Tutorial, or any other tutorial you can find, it will be explained to you in the first minutes.
Update: as suggested by michael.hor257k in the comments, you can also parse the escaped data by hand using string manipulation functions. As he already says in the comments, this is laborious and error-prone, but sometimes, esp. if the XML is not really XML after unescaping, but something like XML, then this may be your only option.

parsing XML to java variables(beans) using JAXB

Am working with the server response with my application. am getting this stuff as response as string.
<Body>
<HotelRQ xmlns="urn:Hotel_Search">
<POS>
<Source Username='USERNAME' Password='PASSWORD' PropertyID='PROPERTYID' />
</POS>
<AvailRequests>
<AvailRequest>
<StayDateRange Start='2009-09-05T12:00:00' End='2009-09-06T12:00:00'/>
<RoomStays>
<RoomStay> <!—for Room 1->
<GuestCounts>
<GuestCount Count='2'/>
</GuestCounts>
<ChildCounts>
<ChildAge Age='10'/>
<ChildAge Age='09'/>
</ChildCounts>
</RoomStay>
</RoomStays>
<SearchCriteria>
<Criterion>
<HotelRef HotelCityName='CITY' HotelName='' Area='' Attraction='' Rating=''/>
<Sorting Preference='2'/>
<ResponseType Compact="Y"/>
</Criterion>
</SearchCriteria>
</AvailRequest>
</AvailRequests>
</HotelRQ>
</Body>
can i use jaxb for this?
i am using this file to parse which i am getting on server response. what i nned to do for parsing it using JAXB. am getting it in String format.and how can i directly map into java class variables or beans?
thanx.
You can see this question: How do I load an org.w3c.dom.Document from XML in a string?
After loading the XML string inside a DOM document, you can call, among others, the method getElementsByTagName to retrieve specific tags and then iterate over them, using getNodeValue to extract the value inside a tag and getAttribute to extract attributes.
You can't easily map it to a Java class with desider fields at runtime, but you can wrap the parsing and extraction of elements inside a class with simple methods like getRooms()

Categories

Resources