XSD Message Validation: Get the name of failing element

nsaini
Participant IV

Hi

I am validating an XML message against an XSD. In case of failure, I need to know the exact element that failed so that correct response can be returned to client. Message validation policy gives line number that failed but not the element name. Can anyone suggest how to achieve this.

{"fault":{"faultstring":"SMV.ValidateRequest failed with reason: \"Expecting a child element but found none [Line 8]\"","detail":{"errorcode":"steps.messagevalidation.Failed"}}}
Solved Solved
1 15 3,562
1 ACCEPTED SOLUTION

Since you mentioned @Dino-at-Google you can check out his Java callout for XSD Validation repo: https://github.com/DinoChiesa/ApigeeEdge-Java-Xsd-Validation

I just happened to be looking at it for the same reason.

View solution in original post

15 REPLIES 15

nsaini
Participant IV

@Dino-at-Google COuld you pls suggest some solution here. Apart from using javascript, what else can I do here

Since you mentioned @Dino-at-Google you can check out his Java callout for XSD Validation repo: https://github.com/DinoChiesa/ApigeeEdge-Java-Xsd-Validation

I just happened to be looking at it for the same reason.

Yes. @NSaini1 , I don't know a way to coerce the builtin Message Validation policy to give you more information, but this Java callout is more verbose and transparent about the errors. Maybe it will bring you joy.

Hi

can we keep the xsd file in proxy resources and access the same from java callout? We are using apigee cloud

Hi, NSaini

I understand your question. I do not know of a way to access an XSD file stored as a proxy resource, from within a Java callout. So, NO: you cannot keep the XSD file as a proxy resource. I think that would be a nice additional capability, but for now it is not possible.

You can store the XSD as a KVM entry.

Hi Dino,

I have tried the java callout. We also need to extract the path of the failing element, where path means name of elements from parent to failing node. We are not able to achieve this and getting below error. Any other way to achieve this?

Java.security.AccessControlException: access denied ("java.io.FilePermission" "/javax.xml.transform.stream.StreamSource@4817e83c" "read") at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) at java.security.AccessController.checkPermission(AccessController.java:884) at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) at com.apigee.securitypolicy.InternalSecurityManager.checkPermission(InternalSecurityManager.java:84) at java.lang.SecurityManager.checkRead(SecurityManager.java:888) at java.io.File.isDirectory(File.java:844) at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:82) at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:188) at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source) at org.apache.xerces.impl.XMLVersionDetector.determineDocVersion(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XMLParser.parse(Unknown Source) at org.apache.xerces.parsers.DOMParser.parse(Unknown Source) at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source) at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:177) at com.google.apigee.edgecallouts.xsdvalidation.XsdValidatorCallout.execute(XsdValidatorCallout.java:249) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$ClassLoadWrappedExecution.execute(JavaCalloutStepDefinition.java:204) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution$1.run(JavaCalloutStepDefinition.java:271) at com.apigee.steps.javacallout.JavaCalloutStepDefinition$SecurityWrappedExecution$1.run(JavaCalloutStepDefinition.java:269) at java.security.AccessController.doPrivileged(Native Method) at

Hi

it looks like you've configured the callout so that it is trying to read a file.

"java.io.FilePermission".

You didn't show the configuration you used for the callout. I can't diagnose it further unless you show that.

ps: the XSD callout cannot read filesystem files.

mgarg
Participant I

@Dino-at-Google to elaborate Navjot's issue, we are customizing the XSD ApigeeEdge-Java-Xsd-Validation and trying to use the DOMSource instead of Streamsource which is using Apache Xerces which sets property in validator having information of current failing node.

We have provided Apache Xerces library in classpath but proxy is not able to read file from this jar and giving

Java.security.AccessControlException: access denied ("java.io.FilePermission" "/javax.xml.transform.stream.StreamSource@4817e83c" "read") at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) at java.security.AccessController.checkPermission(AccessController.java:884) at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) at com.apigee.securitypolicy.InternalSecurityManager.checkPermission(InternalSecurityManager.java:84) at java.lang.SecurityManager.checkRead(SecurityManager.java:888) at java.io.File.isDir

We are referring implementation for this from the following blog

https://stackoverflow.com/questions/38577102/get-parent-element-on-xsd-validation-error

yes, ok, I understand.

The XSD callout that you referenced, at https://github.com/DinoChiesa/ApigeeEdge-Java-Xsd-Validation , does not use Xerces.

I see you said you are customizing this callout to use Xerces. I implemented this callout some time ago; it does not use Xerces. I don't know if that is possible or workable. I don't remember why I didn't use Xerces, but it may have been a compatibility issue with Apigee Edge.

From the stacktrace you included, It looks like the Xerces library, or perhaps your modified code, is calling java.io.File.isDir .

This will be a prohibited operation within a callout inside Apigee Edge. You cannot call that method.

Therefore, either you need to eliminate that call from your modification, or you need to avoid using Xerces (or modify Xerces so that it does not call java.io.File.isDir ).

Hi Manish

I've updated the Java callout to optionally use a DOMSource and populate the failing element.

Pull from the repo to get this new capability.

It's v1.0.6 of the jar.

Thanks Dino.

mgarg
Participant I

Hi Dino,

@Dino-at-Google

When request XML is not having adjacent mandatory fields then java callout is giving error for one fields only. we are expecting error for both the fields.

Can you please check.

Regards

Manish

This callout collects all validation errors and returns them in one go.

https://github.com/yuriylesyuk/edge-soap-validate

Why would you want to use dom instead of stax? It would be slower and will add a ram overhead?

The reason people use DOMSource is to be able to get line numbers referring to the XML doc, in case of errors.

Good point. Luckily it's not true nowadays. SAXParser correctly populates lineNumber and columnNumber of a SAXPaserException. Fixed now:

curl -d @request-with-errors.xml http://dbcedge-eval-prod.apigee.net/rm-localcollection
ERROR: [1, 459] cvc-pattern-valid: Value '****' is not facet-valid with respect to pattern '[a-zA-Z0-9/\-]*' for type 'applicationId'.
ERROR: [1, 459] cvc-type.3.1.3: The value '****' of element 'applicationId' is not valid.
ERROR: [1, 522] cvc-pattern-valid: Value '*****' is not facet-valid with respect to pattern '[a-zA-Z0-9/\-]*' for type 'applicationId'.
ERROR: [1, 522] cvc-type.3.1.3: The value '*****' of element 'intermediaryId' is not valid.
ERROR: [1, 562] cvc-pattern-valid: Value '*****' is not facet-valid with respect to pattern '[a-zA-Z0-9/\-]*' for type 'transactionId'.
ERROR: [1, 562] cvc-type.3.1.3: The value '*****' of element 'transactionId' is not valid.
ERROR: [1, 1131] cvc-complex-type.2.4.a: Invalid content was found starting with element 'geoLocation'. One of '{locationType, radius}' is expected.	

Here is another phenomenon we can observe.

When I send a multi-line xml datagram during unit testing, I can see l EOLs preserved (below).

When sent via Edge (above), the datagram is a single line. So only columnPosition changes. Obviously, \n are lost somewhere during processing. Saying that, the coords point at same location in both cases.

ERROR: [21, 40] cvc-pattern-valid: Value '****' is not facet-valid with respect to pattern '[a-zA-Z0-9/\-]*' for type 'applicationId'.
ERROR: [21, 40] cvc-type.3.1.3: The value '****' of element 'applicationId' is not valid.
ERROR: [24, 43] cvc-pattern-valid: Value '*****' is not facet-valid with respect to pattern '[a-zA-Z0-9/\-]*' for type 'applicationId'.
ERROR: [24, 43] cvc-type.3.1.3: The value '*****' of element 'intermediaryId' is not valid.
ERROR: [26, 41] cvc-pattern-valid: Value '*****' is not facet-valid with respect to pattern '[a-zA-Z0-9/\-]*' for type 'transactionId'.
ERROR: [26, 41] cvc-type.3.1.3: The value '*****' of element 'transactionId' is not valid.
ERROR: [56, 17] cvc-complex-type.2.4.a: Invalid content was found starting with element 'geoLocation'. One of '{locationType, radius}' is expected.