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.
Related
I have an xsd as follows:
<xs:complexType name="exampleDataType">
<xs:sequence>
<xs:element name="payload" type="xs:anyType" minOccurs="0"/>
<xs:element name="message" type="tns:message" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
However when I try to get the payload value from java it returns null. Can anyone help me with this?
I have also faced this issue recently, below is the workaround:
XSD:
Java Code:
ClassLoader classLoader = new XmlToObject().getClass().getClassLoader();
File file = new File(classLoader.getResource("myXmlFile.xml").getFile());
JAXBContext jaxbContext = JAXBContext.newInstance(MyPojo.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
MyPojo myPojo = (MyPojo) jaxbUnmarshaller.unmarshal(file);
Object check = myPojo.getCheck();
if (check instanceof Node) {
ElementNSImpl checkElement = (ElementNSImpl) check;
System.out.println("check=" + checkElement.getTextContent());
}
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.
I am trying to validate an in-memory xml document before writing it into a file. I found many similar questions to my problem, but there is a difference here, I would think so.
Multiple schemas are defined for this validation and the "redefine" option is used in their relationships, from parent to children, as follows:
CoreSchema.xsd -> CenterSchema.xsd -> CenterSchema_REF.xsd
CoreSchema.xsd (just sample, not complete, due to security policy)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.example.com/supplier" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/supplier" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.8">
<xs:element name="NewIssue">
<xs:annotation>
<xs:documentation>Root element to add new issues</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="NewIssueList">
<xs:annotation>
<xs:documentation>Contains a list of issues</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="Issue" type="ImportIssueType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
...
...
CenterSchema.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.example.com/supplier" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://http://www.example.com/supplier" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.8">
<xs:redefine schemaLocation="CoreSchema.xsd">
<xs:complexType name="Issue">
<xs:complexContent>
<xs:extension base="Issue">
<xs:sequence>
<xs:element name="Component" type="Components"/>
<xs:element name="Keywords" type="Keywords" minOccurs="0"/>
<xs:element name="SupplierStatus" type="SupplierStatus" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="ImportIssueType">
<xs:annotation>
<xs:documentation>Definition of a exported issue</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:extension base="ImportIssueType">
<xs:sequence>
<xs:element name="Component" type="Components">
<xs:annotation>
<xs:documentation>Describes the component where the issue occurs.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Keywords" type="Keywords" minOccurs="0">
<xs:annotation>
<xs:documentation>Keyword applied for the issue.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
...
...
</xs:redefine>
</xs:schema>
CenterSchema_REF.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.example.com/supplier" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/supplier" elementFormDefault="qualified" attributeFormDefault="unqualified" version="4.7">
<xs:redefine schemaLocation="CenterSchema.xsd">
...
...
</xs:redefine>
EDITED:The serialized document (written in .xml file) looks like this:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<NewIssue xmlns="http://www.example.com/supplier" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/supplier CenterSchema_REF.xsd">
<NewIssueList>
<Issue>
<SupplierID>574</SupplierID>
<NewIssueMode>Read Only</NewIssueMode>
<Author>
<Name/>
</Author>
<Category>Software</Category>
<ItemType>Test-Issue</ItemType>
<IssueClass>Issue</IssueClass>
<DetectedOnDate>2014-08-14</DetectedOnDate>
<Device>TEST</Device>
<Severity>1</Severity>
<Supplier>
<ContactName/>
<Data>Analysis: [Reason of problem] [Condition for defect] [Impact] [Risk] [Root cause]</Data>
<Status>Supplier Not Assigned</Status>
<StatusInternal>SUBMITTED</StatusInternal>
</Supplier>
...
...
</Issue>
</NewIssueList>
</NewIssue>
I implemented the SchemaFactory and validation as follows:
private boolean toFile(final String outputPath, final Node document) {
boolean resultOk = false;
try {
DOMSource domSource = new DOMSource(document);
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
factory.setResourceResolver(new CustomResourceResolver());
try {
InputStream schemaCSREF = DxiParser.class.getResourceAsStream("/CenterSchema_REF.xsd");
factory.setFeature("http://apache.org/xml/features/honour-all-schemaLocations", true);
factory.setFeature("http://apache.org/xml/features/validation/schema-full-checking", false);
Source source = new StreamSource(schemaCSREF);
Schema schema = factory.newSchema(source);
Validator validator = schema.newValidator();
validator.validate(domSource);
} catch (SAXException e) {
// instance document is invalid!
System.out.println(e.getLocalizedMessage());
System.out.println("\n** SAX Parser: Error during validation of " +document.getNodeName());
return false;
}
FileOutputStream xmlOut = new FileOutputStream(new File(outputPath));
StreamResult streamResult = new StreamResult(xmlOut);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
// serializer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,"users.dtd");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.transform(domSource, streamResult);
xmlOut.close();
resultOk = true;
// ---- Error handling ----
} catch (TransformerConfigurationException tce) {
System.out.println("\n** Transformer Factory error");
System.out.println(" " + tce.getMessage());
Throwable e = (tce.getException() != null) ? tce.getException()
: tce;
e.printStackTrace();
} catch (TransformerException tfe) {
System.out.println("\n** Transformation error");
System.out.println(" " + tfe.getMessage());
Throwable e = (tfe.getException() != null) ? tfe.getException()
: tfe;
e.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return resultOk;
}
CustomResourceResolver is implemented like this:
public class CustomResourceResolver implements LSResourceResolver {
#Override
public LSInput resolveResource(String type, String namespaceURI,
String publicId, String systemId, String baseURI) {
LSInputImpl input = new LSInputImpl();
InputStream stream = null;
try {
stream = new FileInputStream(new File(systemId));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
input.setPublicId(publicId);
input.setSystemId(systemId);
input.setBaseURI(baseURI);
input.setCharacterStream(new InputStreamReader(stream));
return input;
}
}
and the LSInput implementation is standard:
public class LSInputImpl implements LSInput{
private Reader characterStream;
private InputStream byteStream;
private String stringData;
private String systemId;
private String publicId;
private String baseURI;
private String encoding;
private boolean certifiedText;
//getters and setters
}
I can confirm that all the schema files are being loaded (found in paths) and populated in the Schema object. I see in the Grammar field of the Schema object, that all the complex types are detected and I see this specific entry loaded in XSComplexTypeDecl's array:
Complex type name='http://www.example.com/supplier,#AnonType_NewIssue', base type name='anyType', content type='ELEMENT', isAbstract='false', hasTypeId='false', final='0', block='0', particle='("http://www.example.com/supplier":NewIssueList)', derivedBy='RESTRICTION'.
so this is proof that the CoreSchema has been reached through CenterSchema which is reached through CenterSchema_REF.
NOTE: When I set factory feature "http://apache.org/xml/features/validation/schema-full-checking" to true, XSComplexTypeDecl field is null.
Tried to add all 3 xsds as Source[], the error is the same. Tried experimenting with setting different factory features to true/false.
I don't know what else to check, totally stuck.
I can put some more information if there is need. Thanks all.
As a workaround, I resolved the issue by actually validating the instance after serialization, by loading it from the file system.
try {
InputStream schemaCSAPC = new FileInputStream(schemaFile);
factory.setFeature("http://apache.org/xml/features/honour-all-schemaLocations", true);
factory.setFeature("http://apache.org/xml/features/validation/schema-full-checking", false);
FileOutputStream xmlOut = new FileOutputStream(new File(outputPath));
StreamResult streamResult = new StreamResult(xmlOut);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
// serializer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,"users.dtd");
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.transform(domSource, streamResult);
xmlOut.close();
Source source = new StreamSource(new FileInputStream(outputPath));
Source shemaSource = new StreamSource(schemaCSREF);
Schema schema = factory.newSchema(shemaSource);
Validator validator = schema.newValidator();
validator.validate(source);
} catch (SAXException e) {
// instance document is invalid!
System.out.println("\n** SAX Parser: Error during validation of " +document.getNodeName());
return false;
}
Still, this is not according to the requirement but at least I am not blocked and can manage.
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.
I’m having a lot of difficuly parsing an .XSD file with a XSOM in Java. I have two .XSD files one defines a calendar and the second the global types. I'd like to be able to read the calendar file and determine that:
calendar has 3 properties
Valid is an ENUM called eYN
Cal is a String
Status is a ENUM called eSTATUS
Calendar.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:gtypes="http://www.btec.com/gtypes"
elementFormDefault="qualified">
<xs:import namespace="http://www.btec.com/gtypes"
schemaLocation="gtypes.xsd"/>
<xs:element name="CALENDAR">
<xs:complexType>
<xs:sequence>
<xs:element name="Valid" type="eYN" minOccurs="0"/>
<xs:element name="Cal" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="gtypes:STRING">
<xs:attribute name="IsKey" type="xs:string" fixed="Y"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="Status" type="eSTATUS" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="eSTATUS">
<xs:simpleContent>
<xs:extension base="gtypes:ENUM"/>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="eYN">
<xs:simpleContent>
<xs:extension base="gtypes:ENUM"/>
</xs:simpleContent>
</xs:complexType>
gtypes.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.btec.com/gtypes"
elementFormDefault="qualified">
<xs:complexType name="ENUM">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="TYPE" fixed="ENUM"/>
<xs:attribute name="derived" use="optional"/>
<xs:attribute name="readonly" use="optional"/>
<xs:attribute name="required" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="STRING">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="TYPE" use="optional"/>
<xs:attribute name="derived" use="optional"/>
<xs:attribute name="readonly" use="optional"/>
<xs:attribute name="required" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
The code from my attempt to access this information is below. I'm pretty new to Java so
any style criticism welcome.
I really need to know
How to I access the complex type cal and see that it's a string?
How do I access the definition of Status to see it's a enumeration of type eSTATUS
emphasized text
I've has several attempts to access the right information via ComplexType and Elements and Content. However I'm just don't get it and I cannot find any examples that help. I expect (hope) the best method is (relatively) simple when you know how. So, once again, if anyone could point me in the right direction that would be a great help.
xmlfile = "Calendar.xsd"
XSOMParser parser = new XSOMParser();
parser.parse(new File(xmlfile));
XSSchemaSet sset = parser.getResult();
XSSchema s = sset.getSchema(1);
if (s.getTargetNamespace().equals("")) // this is the ns with all the stuff
// in
{
// try ElementDecls
Iterator jtr = s.iterateElementDecls();
while (jtr.hasNext())
{
XSElementDecl e = (XSElementDecl) jtr.next();
System.out.print("got ElementDecls " + e.getName());
// ok we've got a CALENDAR.. what next?
// not this anyway
/*
*
* XSParticle[] particles = e.asElementDecl() for (final XSParticle p :
* particles) { final XSTerm pterm = p.getTerm(); if
* (pterm.isElementDecl()) { final XSElementDecl ed =
* pterm.asElementDecl(); System.out.println(ed.getName()); }
*/
}
// try all Complex Types in schema
Iterator<XSComplexType> ctiter = s.iterateComplexTypes();
while (ctiter.hasNext())
{
// this will be a eSTATUS. Lets type and get the extension to
// see its a ENUM
XSComplexType ct = (XSComplexType) ctiter.next();
String typeName = ct.getName();
System.out.println(typeName + newline);
// as Content
XSContentType content = ct.getContentType();
// now what?
// as Partacle?
XSParticle p2 = content.asParticle();
if (null != p2)
{
System.out.print("We got partical thing !" + newline);
// might would be good if we got here but we never do :-(
}
// try complex type Element Decs
List<XSElementDecl> el = ct.getElementDecls();
for (XSElementDecl ed : el)
{
System.out.print("We got ElementDecl !" + ed.getName() + newline);
// would be good if we got here but we never do :-(
}
Collection<? extends XSAttributeUse> c = ct.getAttributeUses();
Iterator<? extends XSAttributeUse> i = c.iterator();
while (i.hasNext())
{
XSAttributeDecl attributeDecl = i.next().getDecl();
System.out.println("type: " + attributeDecl.getType());
System.out.println("name:" + attributeDecl.getName());
}
}
}
Well after a lot googling I think I've answered my own question. My proposed solution was hopelessly wide of the mark.
The main problem was that the XSD has three namespaces and I was looking in the wrong one for the wrong thing.
If you're looking to parse an XSD in XSOM be sure you understand the structure of the XSD and what the tags mean before you start - it will save you a lot of time.
I'll post my version below as I'm sure it can be improved!
Some links that were helpful:
http://msdn.microsoft.com/en-us/library/ms187822.aspx
http://it.toolbox.com/blogs/enterprise-web-solutions/parsing-an-xsd-schema-in-java-32565
http://www.w3schools.com/schema/el_simpleContent.asp
package xsom.test
import com.sun.xml.xsom.parser.XSOMParser;
import com.sun.xml.xsom.XSComplexType;
import com.sun.xml.xsom.XSContentType;
import com.sun.xml.xsom.XSElementDecl;
import com.sun.xml.xsom.XSModelGroup;
import com.sun.xml.xsom.XSParticle;
import com.sun.xml.xsom.XSSchema;
import com.sun.xml.xsom.XSSchemaSet;
import com.sun.xml.xsom.XSTerm;
import java.util.Iterator;
import java.io.File;
import java.util.HashMap;
public class mappingGenerator
{
private HashMap mappings;
public mappingGenerator()
{
mappings = new HashMap();
}
public void generate(String xmlfile) throws Exception
{
// with help from
// http://msdn.microsoft.com/en-us/library/ms187822.aspx
// http://it.toolbox.com/blogs/enterprise-web-solutions/parsing-an-xsd-schema-in-java-32565
// http://www.w3schools.com/schema/el_simpleContent.asp
XSOMParser parser = new XSOMParser();
parser.parse(new File(xmlfile));
XSSchemaSet sset = parser.getResult();
// =========================================================
// types namepace
XSSchema gtypesSchema = sset.getSchema("http://www.btec.com/gtypes");
Iterator<XSComplexType> ctiter = gtypesSchema.iterateComplexTypes();
while (ctiter.hasNext())
{
XSComplexType ct = (XSComplexType) ctiter.next();
String typeName = ct.getName();
// these are extensions so look at the base type to see what it is
String baseTypeName = ct.getBaseType().getName();
System.out.println(typeName + " is a " + baseTypeName);
}
// =========================================================
// global namespace
XSSchema globalSchema = sset.getSchema("");
// local definitions of enums are in complex types
ctiter = globalSchema.iterateComplexTypes();
while (ctiter.hasNext())
{
XSComplexType ct = (XSComplexType) ctiter.next();
String typeName = ct.getName();
String baseTypeName = ct.getBaseType().getName();
System.out.println(typeName + " is a " + baseTypeName);
}
// =========================================================
// the main entity of this file is in the Elements
// there should only be one!
if (globalSchema.getElementDecls().size() != 1)
{
throw new Exception("Should be only elment type per file.");
}
XSElementDecl ed = globalSchema.getElementDecls().values()
.toArray(new XSElementDecl[0])[0];
String entityType = ed.getName();
XSContentType xsContentType = ed.getType().asComplexType().getContentType();
XSParticle particle = xsContentType.asParticle();
if (particle != null)
{
XSTerm term = particle.getTerm();
if (term.isModelGroup())
{
XSModelGroup xsModelGroup = term.asModelGroup();
term.asElementDecl();
XSParticle[] particles = xsModelGroup.getChildren();
String propertyName = null;
String propertyType = null;
XSParticle pp =particles[0];
for (XSParticle p : particles)
{
XSTerm pterm = p.getTerm();
if (pterm.isElementDecl())
{
propertyName = pterm.asElementDecl().getName();
if (pterm.asElementDecl().getType().getName() == null)
{
propertyType = pterm.asElementDecl().getType().getBaseType().getName();
}
else
{
propertyType = pterm.asElementDecl().getType().getName();
}
System.out.println(propertyName + " is a " + propertyType);
}
}
}
}
return;
}
}
The output from this is:
ENUM is a string
STRING is a string
eSTATUS is a ENUM
eYN is a ENUM
Valid is a eYN
Cal is a STRING
Status is a eSTATUS