Issue:
We have several services that generate a fair amount of XML via XSLT. We don't have any XSD's. I have taken the time to create the XSD's and want to confirm they are correct. Currently I am attempting to verify that the XSD and the XML are validate correctly.
Problem:
I have an xsd(common.xsd) that is imported into all the xsd's. It is not publicly hosted yet, so only recently I found putting the full path of the common.xsd in the AccountList.xsd I was able to get further. I am now receiving the following:
org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 70; s4s-att-invalid-value: Invalid attribute value for 'type' in element 'element'. Recorded reason: UndeclaredPrefix: Cannot resolve 'common:response' as a QName: the prefix 'common' is not declared.
I am at a loss. I cannot find an example that has been asked in forums or a source code snippet that gets a success. I'd appreciate any assistance in getting this to successfully validate my xml.
common.xsd
<xs:schema version="1.0" elementFormDefault="qualified" attributeFormDefault="unqualified"
xmlns="http://www.myorg.com/xsd/gen_fin"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.myorg.com/xsd/gen_fin">
<xs:complexType name="response">
<xs:sequence>
<xs:element name="code" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
AccountList.xsd
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema version="1.0" elementFormDefault="qualified" attributeFormDefault="unqualified"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.myorg.com/xsd/accList"
targetNamespace="http://www.myorg.com/xsd/accList"
xmlns:common="http://www.myorg.com/xsd/gen_fin">
<xs:import namespace="http://www.myorg.com/xsd/gen_fin"
schemaLocation="/home/me/dev/projects/svn/myorg/xsd/src/main/resources/bg/gen_resp/common.xsd"/>
<xs:element name="fundamo">
<xs:complexType>
<xs:sequence>
<xs:element name="response" type="common:response" minOccurs="1" maxOccurs="1"/>
<xs:element name="transaction" type="tns:transaction" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="transaction">
<xs:sequence>
<xs:element name="transactionRef" type="xs:string"/>
<xs:element name="dateTime" type="xs:string"/>
<xs:element name="userName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Test.java
final InputStream commonXsdStream = getXsd(BG_GEN_RESP_XSD_PATH, COMMON);
ClassPathResource fullXsdListing = new ClassPathResource(BG_GEN_RESP_XSD_PATH);
File[] allXsds = fullXsdListing.getFile().listFiles();
for (File currentXsd : allXsds) {
final int filenameLength = currentXsd.getName().length();
final String filenameSanExt = currentXsd.getName().substring(0, filenameLength - 4);
if (!IGNORE.contains(filenameSanExt)) {
final InputStream xsltStream = getXslt(BG_GEN_RESP_XSLT_PATH, filenameSanExt);
final InputStream xsdStream = getXsd(BG_GEN_RESP_XSD_PATH, filenameSanExt);
TransformerFactory xmlTransformer = TransformerFactory.newInstance();
Templates xsltTemplate = xmlTransformer.newTemplates(new StreamSource(xsltStream));
final XSLToXMLConvertor converter = new XSLToXMLConvertor();
String generatedXml = converter.getXML(inputData, xsltTemplate);
LOG.info(generatedXml);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(lnew StreamSource(xsdStream));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(generatedXml)));
/*
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilderFactory.setNamespaceAware(true);
docBuilderFactory.setValidating(true);
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
docBuilder.parse(new InputSource(new ByteArrayInputStream(generatedXml.getBytes("utf-8"))));
*/
}
}
}
It's usually a good idea to have a namespace and targetNamespace defined, although as Petru Gardea pointed out, not strictly necessary. Here's a combination that absolutely works:
AccountList.xsd
<xs:schema
version="1.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.myorg.com/xsd/accList"
targetNamespace="http://www.myorg.com/xsd/accList"
xmlns:common="http://www.myorg.com/xsd/gen_fin">
<xs:import namespace="http://www.myorg.com/xsd/gen_fin" schemaLocation="common.xsd" />
<xs:element name="fundamo">
<xs:complexType>
<xs:sequence>
<xs:element name="response" type="common:response"
minOccurs="1" maxOccurs="1" />
<xs:element name="transaction" type="tns:transaction"
minOccurs="0" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="transaction">
<xs:sequence>
<xs:element name="transactionRef" type="xs:string" />
<xs:element name="dateTime" type="xs:string" />
<xs:element name="userName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
common.xsd
<xs:schema
version="1.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
xmlns="http://www.myorg.com/xsd/gen_fin"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.myorg.com/xsd/gen_fin">
<xs:complexType name="response">
<xs:sequence>
<xs:element name="code" type="xs:string" />
<xs:element name="description" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
NewFile.xml (based on that schema):
<tns:fundamo xmlns:p="http://www.myorg.com/xsd/gen_fin"
xmlns:tns="http://www.myorg.com/xsd/accList" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.myorg.com/xsd/accList AccountList.xsd ">
<tns:response>
<p:code>p:code</p:code>
<p:description>p:description</p:description>
</tns:response>
</tns:fundamo>
ValidateXml.java:
import java.io.File;
import java.io.IOException;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class ValidateXml {
/**
* #param args
*/
public static void main(String[] args) {
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder parser = documentBuilderFactory.newDocumentBuilder();
Document document = parser.parse(new File("NewFile.xml"));
Schema schema = schemaFactory.newSchema(new File("AccountList.xsd"));
Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
You error related to "cannot find the declaration of element" is usually related to the XML document not being namespace-aware. Verify that your path to both XSDs is correct, and go back to the block of code where you build an XML document that is namespace-aware.
Related
I managed to create the classes from an xsd file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="author" type="author"/>
<xs:element name="book" type="book"/>
<xs:complexType name="author">
<xs:sequence>
<xs:element name="firstName" type="xs:string" minOccurs="0"/>
<xs:element name="lastName" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="book">
<xs:sequence>
<xs:element ref="author" minOccurs="0"/>
<xs:element name="pages" type="xs:int"/>
<xs:element name="publicationDate" type="xs:dateTime" minOccurs="0"/>
<xs:element name="title" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
but I can't generate the same classes from a String representing the same xsd.
I pasted my code below:
the main_working generates the classes from a file and works fine
while the main_not_working throws an exception.
This is the code:
import java.io.File;
import java.io.StringReader;
import org.xml.sax.InputSource;
import com.sun.codemodel.JCodeModel;
import com.sun.tools.xjc.api.S2JJAXBModel;
import com.sun.tools.xjc.api.SchemaCompiler;
import com.sun.tools.xjc.api.XJC;
public class XsdMain {
private static File out = new File("out");
private static String xsd =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<xs:schema version=\"1.0\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" +
"<xs:element name=\"author\" type=\"author\"/>" +
"<xs:element name=\"book\" type=\"book\"/>" +
"<xs:complexType name=\"author\">" +
"<xs:sequence>" +
"<xs:element name=\"firstName\" type=\"xs:string\" minOccurs=\"0\"/><xs:element name=\"lastName\" type=\"xs:string\" minOccurs=\"0\"/>" +
"</xs:sequence>" +
"</xs:complexType>" +
"<xs:complexType name=\"book\">" +
"<xs:sequence>" +
"<xs:element ref=\"author\" minOccurs=\"0\"/>" +
"<xs:element name=\"pages\" type=\"xs:int\"/>" +
"<xs:element name=\"publicationDate\" type=\"xs:dateTime\" minOccurs=\"0\"/>" +
"<xs:element name=\"title\" type=\"xs:string\" minOccurs=\"0\"/>" +
"</xs:sequence>" +
"</xs:complexType>" +
"</xs:schema>";
public static void main(String[] args) throws Exception {
main_working(); // this works
main_not_working(); // this doesn't work
}
public static void main_working() throws Exception {
// Setup schema compiler
SchemaCompiler sc = XJC.createSchemaCompiler();
sc.forcePackageName("com.xyz.schema");
// Setup SAX InputSource
File schemaFile = new File("in/test.xsd");
InputSource is = new InputSource(schemaFile.toURI().toString());
// Parse & build
sc.parseSchema(is);
S2JJAXBModel model = sc.bind();
JCodeModel jCodeModel = model.generateCode(null, null);
jCodeModel.build(out);
}
public static void main_not_working() throws Exception {
// Setup schema compiler
SchemaCompiler sc = XJC.createSchemaCompiler();
sc.forcePackageName("com.xyz.schema");
// Setup SAX InputSource
InputSource is = new InputSource( new StringReader( xsd ) );
// Parse & build
sc.parseSchema(is);
S2JJAXBModel model = sc.bind();
JCodeModel jCodeModel = model.generateCode(null, null);
jCodeModel.build(out);
}
}
And the exeption thrown is this one:
Exception in thread "main" java.lang.NullPointerException
at java.net.URI$Parser.parse(URI.java:3035)
at java.net.URI.<init>(URI.java:607)
at com.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.checkAbsoluteness(SchemaCompilerImpl.java:163)
at com.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.parseSchema(SchemaCompilerImpl.java:130)
at com.madx.XsdMain.main_not_working(XsdMain.java:71)
at com.madx.XsdMain.main(XsdMain.java:42)
See http://docs.oracle.com/javase/7/docs/api/org/xml/sax/InputSource.html#setCharacterStream(java.io.Reader)
Application writers should use setSystemId() to provide a base for resolving relative URIs, and may use setPublicId to include a public identifier.
You're probably getting a nullpointer because SystemId isn't set.
Using JAVA 7, XJC.
The xsd is provided by a 3rd party that uses .NET.
The issue at hand is that when I marshal the object into XML I get something along these lines:
<SalesOrder xmlns:ns2="http://schemas.datacontract.org/2004/07/RKLServiceQueue">
<ns2:BillToAddrLine1>7315 N Ritter Ave</ns2:BillToAddrLine1>
<ns2:BillToAddrLine2></ns2:BillToAddrLine2>
<ns2:BillToAddrName>David Kruse</ns2:BillToAddrName>
<ns2:BillToCity>Indianapolis</ns2:BillToCity>
<ns2:BillToCountryID>USA</ns2:BillToCountryID>
<ns2:BillToPostalCode>46250</ns2:BillToPostalCode>
</SalesOrder
The service is expecting something like this:
<SalesOrder xmlns="http://schemas.datacontract.org/2004/07/RKLServiceQueue">
<BillToAddrLine1>String content</BillToAddrLine1>
BillToAddrLine2>String content</BillToAddrLine2>
<BillToAddrLine3>String content</BillToAddrLine3>
<BillToAddrLine4>String content</BillToAddrLine4>
<BillToAddrLine5>String content</BillToAddrLine5>
<BillToAddrName>String content</BillToAddrName>
<BillToCity>String content</BillToCity>
</SalesOrder>
Here is part of the xsd as well
<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/RKLServiceQueue" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/RKLServiceQueue" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="SalesOrder">
<xs:sequence>
<xs:element minOccurs="0" name="BillToAddrLine1" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToAddrLine2" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToAddrLine3" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToAddrLine4" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToAddrLine5" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToAddrName" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToCity" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToCountryID" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToPostalCode" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="BillToStateID" nillable="true" type="xs:string" />
I have conducted test on SoapUI to verify.
I have done a bit of searching on the web, including stackoverflow and it points to using NamespacePrefixMapper but that does not seem to do the the trick. I keep getting the following exception:
javax.xml.bind.PropertyException: name: com.sun.xml.internal.bind.marshaller.namespacePrefixMapper value: com.heritage.jobs.MyPrefixMapper#29545330
Here is the mapper
import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper;
/**
*
*/
public class MyPrefixMapper extends NamespacePrefixMapper
{
private static final String FOO_PREFIX = ""; // DEFAULT NAMESPACE
private static final String FOO_URI = "http://schemas.datacontract.org/2004/07/RKLServiceQueue";
/*
* (non-Javadoc)
*
* #see com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper#getPreferredPrefix(java.lang.String,
* java.lang.String, boolean)
*/
#Override
public String getPreferredPrefix(final String pNameSpaceUri, final String pSuggestion, final boolean pRequirePrefix)
{
if (FOO_URI.equals(pNameSpaceUri))
{
return FOO_PREFIX;
}
return pSuggestion;
}
Here is what I am using to call it:
final JAXBContext context = JAXBContext.newInstance(SalesOrder.class);
marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
final MyPrefixMapper prefixMapper = new MyPrefixMapper();
try
{
marshaller.setProperty("com.sun.xml.internal.bind.marshaller.namespacePrefixMapper", prefixMapper);
}
catch (final PropertyException e)
{
LOG.error("perform(CronJobModel)", e);
}
I am not clear as to what I am missing to make this work - How can I remove the namespace ns from each of the fields/properties?
Try using the annotations in package-info.java like this:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://myOutput", xmlns = {#XmlNs(prefix = "", namespaceURI = "http://myOutput")}, elementFormDefault = XmlNsForm.QUALIFIED)
This way I got rid of the ns2 on the root element...
Try removing internal in import and in property like this:
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
... and,
marshaller.setProperty("com.sun.xml.bind.marshaller.namespacePrefixMapper", prefixMapper);
You could use the following code:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.newDocument();
JAXBContext context = JAXBContext.newInstance(RequestXml.class);
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(new RequestXml(), document);
new NamespaceRemover().remove(document);
StringWriter writer = new StringWriter();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult(writer));
System.out.println(writer.toString());
The NamespaceRemover is implemented as follows:
public class NamespaceRemover {
public void remove(Node node) {
Document doc = node.getOwnerDocument();
String localName = tryToResolveLocalName(node.getNodeName());
if (localName != null)
doc.renameNode(node, null, localName);
NamedNodeMap attributes = node.getAttributes();
if (attributes != null)
remove(attributes);
remove(node.getChildNodes());
}
protected String tryToResolveLocalName(String nodeName) {
if (nodeName == null || nodeName.startsWith("#"))
return null;
String[] tagParts = nodeName.split(":");
return tagParts[tagParts.length - 1];
}
public void remove(NodeList childNodes) {
for (int i = 0; i < childNodes.getLength(); i++)
remove(childNodes.item(i));
}
public void remove(NamedNodeMap attributes) {
List<String> attrsToBeRemoved = new ArrayList<>();
for (int i = 0; i < attributes.getLength(); i++) {
Node attr = attributes.item(i);
if (attr.getNodeName().startsWith("xmlns:") || "xmlns".equals(attr.getNodeName()))
attrsToBeRemoved.add(attr.getNodeName());
else
remove(attributes.item(i));
}
for (String attrToBeRemoved : attrsToBeRemoved)
attributes.removeNamedItem(attrToBeRemoved);
}
}
The NamespaceRemover can also be used to remove namespaces from sub-trees of your XML document.
I have two xsds from which i have generated jaxb pojos using xjc. And i have generated XMLs using jaxb marshaller with jaxb-impl-2.2.6
For this I have overriden NamespacePrefixMapper as MyNamespacePrefixMapper
Parent.xsd
<xs:schema targetNamespace="parent"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:Env="Parent"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:child="urn:xsd:child">
<xs:import namespace="urn:xsd:child" schemaLocation="child.xsd"/>
<xs:element name="parent">
<xs:complexType>
<xs:sequence>
<xs:element name="child" type="child:child1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
child.xsd
<xs:schema xmlns="urn:xsd:child" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:xsd:child">
<xs:element name="child" type="child1"/>
<xs:complexType name="child1">
<xs:sequence>
<xs:element name="Id" type="Max20Text"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="Max20Text">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
XmlMarshallingTest.java
import javax.xml.bind.*;
import javax.xml.stream.XMLStreamException;
import org.junit.Test;
import parent.Parent;
import xsd.child.Child1;
public class XmlMarshallingTest {
#Test
public void testXmlMarshalling() throws JAXBException, XMLStreamException{
Parent envelope = new Parent();
Child1 businessApplicationHeaderV01 = new Child1();
businessApplicationHeaderV01.setId("ABC123");
envelope.setChild(businessApplicationHeaderV01);
JAXBContext context = JAXBContext.newInstance(envelope.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new MyNamespacePrefixMapper());
marshaller.marshal(envelope, System.out);
}
}
MyNamespacePrefixMapper.java
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
public class MyNamespacePrefixMapper extends NamespacePrefixMapper {
#Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean arg2) {
if("Parent".equals(namespaceUri)) {
return "parentPrefix";
} else if("urn:xsd:child".equals(namespaceUri)) {
return "childPrefix";
}
return "defaultPrefix";
}
}
the generated xml is like
<parentPrefix:parent xmlns:childPrefix="urn:xsd:child" xmlns:parentPrefix="parent">
<parentPrefix:child>
<childPrefix:Id>ABC123</childPrefix:Id>
</parentPrefix:child>
</parentPrefix:parent>
Here, my problem is , I expect the xml to be look like following
<parentPrefix:parent xmlns:childPrefix="urn:xsd:child" xmlns:parentPrefix="parent">
<childPrefix:child>
<childPrefix:Id>ABC123</childPrefix:Id>
</childPrefix:child>
</parentPrefix:parent>
I expect the prefix of child tag to be "childPrefix" but it shows "parentPrefix"
The parent tag is well generated with prefix "parentPrefix"
Environment Description
Maven 3.0.4
Java version: 1.7.0_04
OS : windows 7
Your schema defines the parent element as having a child element named child in the parent schema's own targetNamespace, whose type happens to come from the child namespace. If you want the parent to use the child element that is defined in the child schema (and thus in the urn:xsd:child namespace) then instead of
<xs:element name="child" type="child:child1"/>
you need
<xs:element ref="child:child"/>
I wrote RESt web service using JERSEY. PFB my end point.
Endpoint class:
package org.madbit.rest;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.madbit.rest.ws.SumRequest;
import org.madbit.rest.ws.SumResponse;
#Path("/services")
public class SumEndpoint {
#POST
#Path("sum")
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_XML)
public SumResponse getSum(SumRequest request) {
SumResponse response = new SumResponse();
List<Integer> elements = request.getElement();
int sum = 0;
for (Integer element: elements)
sum += element;
response.setSum(sum);
return response;
}
}
XSD:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.madbit.org/SumService" xmlns:tns="http://www.madbit.org/SumService" elementFormDefault="qualified">
<xs:element name="SumRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="element" type="xs:int" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SumResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="sum" type="xs:int" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I have generated POJOs from above xsd using Maven JAXB plugin. now i have SumRequest and SumResponse POJOs.
Now how can i write a Jersey client to get the response by passing below input?
<?xml version="1.0" encoding="ISO-8859-1"?>
<SumRequest xmlns="http://www.madbit.org/SumService">
<element>1</element>
<element>4</element>
</SumRequest>
Thanks!
This should work for you:
public static void testWS(){
try{
SumRequest sumRequest = new SumRequest(1,4); //here you have to create your input object
Client client = Client.create();
WebResource service = client.resource("http://www.madbit.org/SumService");
/*
* here you are calling the post method with your input object attached
*/
ClientResponse response = service.type(MediaType.APPLICATION_XML).post(ClientResponse.class, sumRequest);
SumResponse res = response.getEntity(SumResponse.class);
System.out.println("output JaxbWS:\n " + res.toString());
}
catch(Exception e){
System.out.println(e.getMessage());
}
I must add that your object SumRequest that you are passing will be automatically converted in XML because you method specifies that consumes XML.
I have followed this tutorial for validating XML files. But I am receiving exception when validating XML file. What I am doing wrong? My codes:
XML schema:
<?xml version="1.0" encoding="utf-8" ?>
<!-- definition of simple elements -->
<xs:element name="first_name" type="xs:string" />
<xs:element name="last_name" type="xs:string" />
<xs:element name="phone" type="xs:string" />
<!-- definition of attributes -->
<xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute name="date" type="xs:date" use="required"/>
<!-- definition of complex elements -->
<xs:element name="reporter">
<xs:complexType>
<xs:sequence>
<xs:element ref="first_name" />
<xs:element ref="last_name" />
<xs:element ref="phone" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="report">
<xs:complexType>
<xs:attribute ref="type"/>
<xs:attribute ref="date" />
<xs:sequence>
<xs:element ref="reporter" />
</xs:sequence>
</xs:complexType>
</xs:element>
XML file to validate:
<?xml version="1.0" encoding="utf-8" ?>
<report type="5" date="2012-12-14">
<reporter>
<first_name>FirstName</firstname>
<last_name>Lastname</lastname>
<phone>+xxxxxxxxxxxx</phone>
</reporter>
</report>
Java source for validating:
import javax.xml.XMLConstants;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import org.xml.sax.SAXException;
import java.io.*;
public class ProtocolValidator
{
public static void main(String [] args) throws Exception
{
Source schemaFile = new StreamSource(new File("schema.xsd"));
Source xmlFile = new StreamSource(new File("test_xml.xml"));
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaFile);
Validator validator = schema.newValidator();
try{
validator.validate(xmlFile);
System.out.println(xmlFile.getSystemId() + " is valid");
}
catch (SAXException e)
{
System.out.println(xmlFile.getSystemId() + " is NOT valid");
System.out.println("Reason: " + e.getLocalizedMessage());
}
}
}
Exception I am receiving:
Exception in thread "main" org.xml.sax.SAXParseException; systemId: file:/root/test/schema.xsd; lineNumber: 4; columnNumber: 50; The prefix "xs" for element "xs:element" is not bound.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)...
The XML schema file itself needs to be a valid XML document. You are missing the outer schema element and the namespace declaration for the xs prefix.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- schema elements here -->
</xs:schema>
Add this line to your schema, just below the first line:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
... and a closing tag as the last line in the schema:
</xs:schema>