Parsing an xml embedded within another xml using XPath Spring - spring

I'm parsing an xml String using the 'evaluate' function provided by Xpath to read the contents embedded within specific tags in the xml. But i'm having trouble while trying to parse an xml which is embeded within a set of tags which i want to parse.
<Channel>
<channelId>SD0987</channelId>
<parameters>
<param>org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://nike-dev.coupahost.com/api/suppliers?return_object=limited]; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request</param>
<param><?xml version="1.0" encoding="UTF-8"?>
<errors>
<error>
<![CDATA[Unable to find valid PaymentTerm record for payment_term with keys {"code"=>"9999"}. Possible keys are ["id", "code"]. Please verify your xml.]]>
</error>
</errors>
</param>
<param>6-5100</param>
<param><?xml version="1.0" encoding="UTF-8"?><supplier><name>SuTestVDR008-6-5100</name><display-name>SuTestVDR008-6 (SANDALS) - VAT Registration Number - Indirect Europe - INACTIVE</display-name><status>active</status><deleted type="boolean">true</deleted><vendor-account-group-code>1001</vendor-account-group-code><vendor-number>SuTestVDR008-6</vendor-number><on-hold type="boolean">false</on-hold><language-code>E</language-code><purchase-organization-code>5100</purchase-organization-code><group-key>1234</group-key><vendor-partner-type-code>Z4</vendor-partner-type-code><currency-code>EUR</currency-code><primary-address><street1>#### JIU BI VILLAGE</street1><street2>77774</street2><city>GUANGZHOU CITY</city><state>190-Guangdong</state><postal-code>511480</postal-code><country><code>CN</code></country></primary-address><payment-term><code>9999</code></payment-term><content-groups><content-group><name>730_Company Code</name></content-group></content-groups><po-method>prompt</po-method><invoice-matching-level>3-way</invoice-matching-level></supplier></param>
</parameters>
</Channel>
In the above xml sample, i need to read and retrieve everything that is within the tags "param".
Currently, i'm first getting a count of the param tags and then looping thru them to get the data within the tags -
paramCount = XPathUtils.evaluate(originalPayload,"count(/Channel/parameters/param)",XPathUtils.STRING);
for(int i=1;i<=pCount;i++){
pList.add(XPathUtils.evaluate(originalPayload, "/Channel/parameters/param[" +i+ "]",XPathUtils.STRING)
}
This works fine with other xmls but not with the sample given above. I get the below error -
"[Fatal Error] :5:17:The processing instruction target matching "[xX][mM][lL]" is not allowed."
If i remove the part "?xmlversion="1.0" encoding="UTF-8"?
it parses the tags but the output is -
org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://nike-dev.coupahost.com/api/suppliers?return_object=limited]; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request
Unable to find valid PaymentTerm record for payment_term with keys {"code"=>"9999"}. Possible keys are ["id", "code"]. Please verify your xml.
6-5100
SuTestVDR008-6-5100SuTestVDR008-6 (SANDALS) - VAT Registration Number - Indirect Europe - INACTIVEactivetrue1001SuTestVDR008-6falseE51001234Z4EUR#### JIU BI VILLAGE77774GUANGZHOU CITY190-Guangdong511480CN9999730_Company Codeprompt3-way
So as you can see, it just captured the content within the various tags and printed it.
My ask is to print all the text in between the
<param >
tags as is with all the indentation in place.
So the output expected is -
org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [https://nike-dev.coupahost.com/api/suppliers?return_object=limited]; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request
<?xml version="1.0" encoding="UTF-8"?>
<errors>
<error>
<![CDATA[Unable to find valid PaymentTerm record for payment_term with keys {"code"=>"9999"}. Possible keys are ["id", "code"]. Please verify your xml.]]>
</error>
</errors>
6-5100
<?xml version="1.0" encoding="UTF-8"?>
<supplier><name>SuTestVDR008-6-5100</name><display-name>SuTestVDR008-6 (SANDALS) - VAT Registration Number - Indirect Europe - INACTIVE</display-name><status>active</status><deleted type="boolean">true</deleted><vendor-account-group-code>1001</vendor-account-group-code><vendor-number>SuTestVDR008-6</vendor-number><on-hold type="boolean">false</on-hold><language-code>E</language-code><purchase-organization-code>5100</purchase-organization-code><group-key>1234</group-key><vendor-partner-type-code>Z4</vendor-partner-type-code><currency-code>EUR</currency-code><primary-address><street1>#### JIU BI VILLAGE</street1><street2>77774</street2><city>GUANGZHOU CITY</city><state>190-Guangdong</state><postal-code>511480</postal-code><country><code>CN</code></country></primary-address><payment-term><code>9999</code></payment-term><content-groups><content-group><name>730_Company Code</name></content-group></content-groups><po-method>prompt</po-method><invoice-matching-level>3-way</invoice-matching-level></supplier>
Any ideas?

For that task your content in the <param> must be wrapped to the <![CDATA[ .. ]]>. Otherwise it becomes as a part of the root XML and loses it purpose to be the relaxed data for the XPath result.

Related

Replace element by XPath

I try to replace some element of my input XML in Citrus Framework.
My Spring context contains:
<citrus:namespace-context>
<citrus:namespace prefix="def" uri="http://sample.com/xmlns/2005"/>
</citrus:namespace-context>
My input file starts with:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<ns0:canonicalMessageHeader xmlns:ns0="http://sample.com/xmlns/2005">
<ns0:headerVersion>1.0</ns0:headerVersion>
<ns0:bodyVersion>1.0</ns0:bodyVersion>
<ns0:trackingInfo>
<ns0:eventHandlerInitInfo>
<ns0:processInfo>
<ns0:adapterTrackingId>214F27DF-E1FB-4E84-9122-390C5876ABD2:1</ns0:adapterTrackingId>
...
My endpoint is configured in that way:
<send endpoint="jms:topic:Order.Request?timeout=10000&connectionFactory=DEVconnectionFactoryFrom">
<message>
<resource file="com/sample/citrus/messages/input/SalesOrderTo.xml"/>
<element value="${track}" path="SOAP-ENV:Envelope/SOAP-ENV:Header/def:canonicalMessageHeader/def:trackingInfo/def:eventHandlerInitInfo/def:processInfo/def:adapterTrackingId"/>
I have the following error:
Can not evaluate xpath expression 'SOAP-ENV:Envelope/SOAP-ENV:Header/def:canonicalMessageHeader/def:trackingInfo/def:eventHandlerInitInfo/def:processInfo/def:adapterTrackingId'
at com/sample/citrus/SalesOrderToIT(sequential:45)
at com/sample/citrus/SalesOrderToIT(send:48-82)
Caused by: javax.xml.xpath.XPathExpressionException: org.apache.xpath.domapi.XPathStylesheetDOM3Exception: Prefix must resolve to a namespace: def
What's the possible cause of this error?
Best Regards
Global namespace declaration support is missing in Citrus when overwriting message elements in a send operation via XPath. This issue has been tracked: https://github.com/christophd/citrus/issues/331
In the meantime you have to use the exact same namespace prefix as in the message template file - in your case ns0:
Also you could throw away XPath overwrite and use the dot notated Node overwrite like this:
<send endpoint="jms:topic:Order.Request?timeout=10000&connectionFactory=DEVconnectionFactoryFrom">
<message>
<resource file="com/sample/citrus/messages/input/SalesOrderTo.xml"/>
<element value="${track}" path="Envelope.Header.canonicalMessageHeader.trackingInfo.eventHandlerInitInfo.processInfo.adapterTrackingId"/>
</message>
</send>
The dot notation is not based on namespaces but uses the local element names for finding the element in the message template. Obviously not as powerful as XPath but it works with current version of the framework.
You defined nso as namespace prefix in XML but then use def on the XPath, should be nso.

ACA IRS status service response with errors

Would it be possible for somebody provide me with example of the ACAGetTransmitterBulkRequestStatus web service response with errors?
I would like to see structure of the attached(if it's in attachment) errors.
Here's an XML with rejection errors:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:FormBCTransmitterSubmissionDtl xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:ns2="urn:us:gov:treasury:irs:common" xmlns:ns3="urn:us:gov:treasury:irs:msg:form1094-1095BCtransmittermessage">
<ACATransmitterSubmissionDetail>
<TransmitterErrorDetailGrp>
<SubmissionLevelStatusCd>Rejected</SubmissionLevelStatusCd>
<UniqueSubmissionId>1095C-16-0000XXXX|1</UniqueSubmissionId>
</TransmitterErrorDetailGrp>
<TransmitterErrorDetailGrp>
<UniqueSubmissionId>1095C-16-0000XXXX|1</UniqueSubmissionId>
<ns2:ErrorMessageDetail>
<ns2:ErrorMessageCd>AIREX126</ns2:ErrorMessageCd>
<ns2:ErrorMessageTxt>Rejected submission - TIN Validation Failed for ALE Member's EIN</ns2:ErrorMessageTxt>
<ns2:XpathContent>EmployerEIN</ns2:XpathContent>
</ns2:ErrorMessageDetail>
</TransmitterErrorDetailGrp>
<TransmitterErrorDetailGrp>
<UniqueRecordId>1095C-16-0000XXXX|1|3</UniqueRecordId>
<ns2:ErrorMessageDetail>
<ns2:ErrorMessageCd>AIRTN500</ns2:ErrorMessageCd>
<ns2:ErrorMessageTxt>TIN Validation Failed</ns2:ErrorMessageTxt>
</ns2:ErrorMessageDetail>
</TransmitterErrorDetailGrp>
</ACATransmitterSubmissionDetail>
</ns3:FormBCTransmitterSubmissionDtl>
You can recreate that same error response by sending invalid EIN's and SSN's that AATS doesn't expect.
If you want to send valid test EIN's, TIN's and names (outside of the IRS AATS test scenarios), please refer to https://www.irs.gov/pub/irs-pdf/p5164.pdf (starting at page 6).
Sample range of valid test EIN's:
EIN RANGE NAME CONTROL
00-0000001 through 00-0000100 HELP
00-0000101 through 00-0000200 HIDE
Sample range of valid test SSN's:
SSN RANGE NAME CONTROL
000-00-0001 through 000-00-0100 HERR
000-00-0101 through 000-00-0200 MART

XSL - Externalizing Xpath queries to a property file

I went through various posts, regarding reading properties from external property files. Looks like there is a function - getProperty, which can read values from a property file, using a key. I am using saxon parser with spring integration. I am trying something like this, as described in the post :-
spring context file:
<int-xml:xslt-transformer id="xsltTransformer" input-channel="bulkStringInboundChannel"
output-channel="toBridgeChannel" result-type="StringResult" **transformer-factory-class="net.sf.saxon.TransformerFactoryImpl"**
xsl-resource="classpath:/META-INF/spring/integration/intake/intake-flow/bulkTransformer.xsl" />
XSL style sheet:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
....
<xsl:variable name="props" select="document('prop.xml')" />
<xsl:value-of select="f:getProperty('query1')"/>
....
Prop.xml:
query1 = /Batch/RequestID/text()
Error description:
XPST0003: XPath syntax error at char 23 on line 30 in {f:getProperty('query1')}:
XTSE0650: No template exists named getProperty
I now have two questions- first of all, how do I get rid of these errors?
Second, can I store xPath queries in property files? The post describes a method, to read a property file and use the value pertaining to its key. However, I am thinking that getProperty will just print the query's text equivalent instead of evaluating the query and processing it. Is there a way to achieve this?
Post - How to read a .properties file inside a .xsl file?
I can't help you with the Spring side of the question, but as for the Saxon side, you can call the JDK method System.getProperty() using code like this:
<xsl:value-of select="System:getProperty('user.dir')" xmlns:System="java:java.lang.System"/>
Java extensibility requires Saxon-PE or higher.
If the value of the property that you read is an XPath expression, you can then execute it using the XSLT 3.0 xsl:evaluate instruction - which also requires Saxon-PE or higher.

IBM Integeration BUS: Trace Node

In simple message flow in which there are 3 nodes. One is MQ input node which is receiving an xml input. Other is MQ Output node which is receiving msg passed from MQ input. In between there is trace node. The trace node is configured to generate trace in a file. it trace down the whole xml msg, its content in the file. What if I want to track a single tag of xml file like contact number.
i.e:
<contactDetails>
<contactName>Acme</contactName>
<contactNumber>09200209</contactNumber>
</contactDetails>
Which pattern should I use? I have tried ${Body.contactDetails.contactNumber} and ${Environment.contactDetails.contactNumber} but I am getting null in output. Can anyone help?
EDIT: Below is the whole message:
<?xml version="1.0" encoding="utf-8"?>
<tns:In_Request xmlns:tns="http://www.ibm.lab.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ActionRequest>O</ActionRequest>
<DateRequest>10/12/2005</DateRequest>
<customerNumber>1</customerNumber>
<customerName>ACME Hardware</customerName>
<customerDetails>
<customerAddress1>1254 Main St</customerAddress1>
<customerAddress2>Suite 12</customerAddress2>
<customerCity>Dime Box</customerCity>
<customerState>TX</customerState>
<customerCountry>USA</customerCountry>
<customerPostalCode>76543</customerPostalCode>
<customerCreditLimit>1200</customerCreditLimit>
<customerCreditScore>123</customerCreditScore>
</customerDetails>
<contactDetails>
<contactFirstName>Freddy</contactFirstName>
<contactLastName>Bloggs</contactLastName>
<contactPhoneNumber>555-123-6543</contactPhoneNumber>
</contactDetails>
<requestDecision>Y</requestDecision>
<comments>Just a Comment</comments>
</tns:In_Request>
I see the problem now.
Body in the reference points to the root element for the domain in which your message is parsed, e.g. to Root.XMLNSC if you set the message domain to XMLNSC on the input node of your message, so not to the root element of your message.
If you want to trace the value of the element contactPhoneNumber from the example message, you should use the following reference:
${Body.*:In_Request.contactDetails.contactPhoneNumber}
So after the Body, you must specify the whole path to your element. The *: part is needed because the root element in your message is in a namespace.

Listing in the output in a specific crawler

i have been making xml template for a specific concern for crawling the jobs of that concern. Am using xpath for making templates but at the the runnable time the crawler is running with out giving error but with out listing the jobs
Eg:the template of Sopra technologies(the url provided in the coding)
<?xml version="1.0" encoding="UTF-8"?>
<site>
<request-type>link</request-type>
<base-url><![CDATA[http://www.in.sopragroup.com/index.htm]]></base-url>
<start-url><![CDATA[http://www.in.sopragroup.com/careers/JobListing.aspx]]>
</start-url>
<data>
<intermediate>
<navigation-request>
<navigation-type>link</navigation-type>
<url>
<xpath></xpath>
<sub-xpath></sub-xpath>
</url>
</navigation-request>
<xpath><![CDATA[//table[#class='bg_lgrey']/tbody/tr[position>2]]></xpath>
<apply-url>
<sub-xpath><![CDATA[td/#href]]></sub-xpath>
</apply-url>
<title>
<sub-xpath><![CDATA[td/a/text()]]></sub-xpath>
</title>
</intermediate>
<detail>
<xpath><![CDATA[//table[#id='tbl']/tbody]]></xpath>
<experience>
<sub-xpath><![CDATA[tr[8]/td[2]/text()]]></sub-xpath>
</experience>
<location>
<sub-xpath><![CDATA[tr[10]/td[2]/text()]]></sub-xpath>
</location>
<description>
<sub-xpath><![CDATA[tr[2]/td[2]/text()]]></sub-xpath>
</description>
</detail>
</data>
</site>
//table[#class='bg_lgrey']/tbody/tr[position>2]
This is one of the problems in the code. Such Xpath expression has chances of selecting something only if the tr element has a child named position whose string value is castable to a number with value greater than 2.
You want:
//table[#class='bg_lgrey']/tbody/tr[position() >2]
A second problem:
The string "bg_lgrey" is not present at all in the source of the pages pointed by the two urls.

Resources