cvc-elt.1: Cannot find the declaration of element 'NewIssue' - java

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.

Related

No URI javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"SearchAndList"). Expected elements are (none)

I am having trouble to unmarshall my data. I got the following error:
ERROR FsceClient - Error in getDataInMatches : unexpected element
(uri:"", local:"SearchAndList"). Expected elements are (none)
requested params:+COUNTRY=US+YR=2016+DIV=Ford+WB=122.0
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"SearchAndList"). Expected elements are (none)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
This is my xml file:
<SearchAndList>
<fvd>
+COUNTRY=US+YR=2016+DIV=Ford+WB=122.0
</fvd>
<sol>
<rsi>
<sType>Ss</sType>
<mHave>true</mHave>
<toAr>0</toAr>
<toAr>0</toAr>
<toAr>22</toAr>
</rsi>
<rsi>
<sType>ssa</sType>
<mHave>true</mHave>
<toAr>77</toAr>
</rsi>
</sol>
<sol>
<rsi>
<sType>sve</sType>
<mHave>false</mHave>
<toAr>0</toAr>
<toAr>21</toAr>
</rsi>
</sol>
</SearchAndList>
This is encountered when the XSD schema does not contain element definitions and only contains class definitions (i.e. complex types).
e.g. for this XSD,
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="bar" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
The object factory created is like this:
#XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
public Foo createFoo() {
return new Foo();
}
}
BUT FOR THIS 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="foo" type="foo" nillable="true"/>
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="bar" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
The ObjectFactory class created by JAXB is:
#XmlRegistry
public class ObjectFactory {
private final static QName _Foo_QNAME = new QName("", "foo");
public ObjectFactory() {
}
public Foo createFoo() {
return new Foo();
}
#XmlElementDecl(namespace = "", name = "foo")
public JAXBElement<Foo> createFoo(Foo value) {
return new JAXBElement<Foo>(_Foo_QNAME, Foo.class, null, value);
}
}
You can see that the JAXBElement wrapper creation method is also added. With the second XSD, the unmarshaller knows what to do when it encounters a tag with name "foo". So if you have an XSD, add "element" definitions as well as the complex types.
----- EDIT----
The sample unmarshaller code:
JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Object result = ((JAXBElement<Object>) jaxbUnmarshaller.unmarshal(stream)).getValue();

XML validation with xsd as Source

I want to validate my xml with xsd sxheme. When I load xsd as new File() - al is ok.
But I can't do this 'xos of .jar. So i use this code to load xsd
public static boolean init() {
try (InputStream isSchema = Thread.currentThread().getContextClassLoader().getResourceAsStream(XSD_PATH)) {
System.out.println(getStringFromInputStream(isSchema));
schemaSource = new StreamSource(isSchema);
}
catch (IOException e) {
logger.debug(e.toString());
return false;
}
return true;
}
isScheme object has valid content of .xsd file. But when I call it
private boolean validateXML(File xmlFile) {
try (InputStream stream = new FileInputStream(xmlFile)) {
Source xmlSource = new StreamSource(stream);
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
.newSchema(schemaSource)
.newValidator()
.validate(xmlSource);
}
catch (Exception e) {
logger.debug("ERROR XML parsing for [" + xmlFile.getName() + "] : " + e.toString());
return false;
}
return true;
}
An error occurs
DEBUG Task:82 - ERROR XML parsing for [test good 4 - копия - копия (380) - копия - копия - копия - копия - копия - копия.xml] : org.xml.sax.SAXParseException; schema_reference.4: Failed to read schema document 'null', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not .
This is my XSD file
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Entry">
<xs:complexType>
<xs:all>
<xs:element name="content">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="1024" />
<xs:minLength value="0" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="creationDate">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:length value="19" />
<xs:pattern value="[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]"></xs:pattern>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xsd:schema>
Example of xml
<?xml version="1.0" encoding="UTF-8"?>
<Entry>
<content>any message</content>
<creationDate>2016-06-15 20:20:20</creationDate>
</Entry>
Help me please.
I change mu code to this
try (InputStream stream = new FileInputStream(xmlFile)) {
isSchema = Thread.currentThread().getContextClassLoader().getResourceAsStream(XSD_PATH);
schemaSource = new StreamSource(isSchema);
Source xmlSource = new StreamSource(stream);
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
.newSchema(schemaSource)
.newValidator()
.validate(xmlSource);
}
and to this
try (InputStream stream = new FileInputStream(xmlFile)) {
InputStream isSchema = Thread.currentThread().getContextClassLoader().getResourceAsStream(XSD_PATH);
Source schemaSource = new StreamSource(isSchema);
Source xmlSource = new StreamSource(stream);
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
.newSchema(schemaSource)
.newValidator()
.validate(xmlSource);
}
But the same error.
Looking at the source of StreamSource here:
The StreamSource constructor which takes InputStream merely calls the setter. So the underlying inputstream must be kept open to be able to read from the streamSource.
When the try within your init() completes, it closes the inputstream, so I the streamsource instance (schemaSource) becomes useless at that point. You will have to open the schema file at the time of validating the XML.

How to remove namespace from generated JAXB

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.

XML validation against xsd's in Java

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.

Parsing XSD Schema with XSOM in Java. How to access element and complex types

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

Categories