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.
Related
I'm working on this for days now and I have no idea why i can't get it working. I created some java code:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
Document doc = null;
try {
builder = factory.newDocumentBuilder();
doc = builder.parse(xsl);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
try {
XPathExpression expr = xpath.compile("//xs:attribute-set[#name = \"tableImportantLine\"]/xs:attribute/text()");
NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
which should read this xsl-fo file:
<?xml version="1.0" encoding="utf-8"?>
<xs:stylesheet xmlns:xs="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
<xs:attribute-set name="cell-style">
<xs:attribute name="border-width">0.5pt</xs:attribute>
<xs:attribute name="border-style">solid</xs:attribute>
<xs:attribute name="border-color">black</xs:attribute>
</xs:attribute-set>
<xs:attribute-set name="block-style">
<xs:attribute name="font-size"> 10pt</xs:attribute>
<xs:attribute name="line-height">15pt</xs:attribute>
<xs:attribute name="start-indent">1mm</xs:attribute>
<xs:attribute name="end-indent"> 1mm</xs:attribute>
</xs:attribute-set>
<xs:attribute-set name="thickText">
<xs:attribute name="font-weight">bold</xs:attribute>
</xs:attribute-set>
<xs:attribute-set name="tableImportantLine">
<xs:attribute name="background-color">#86f442</xs:attribute>
</xs:attribute-set>
<xs:attribute-set name="tableOutlineStyle">
<xs:attribute name="border">solid 0.5mm black</xs:attribute>
</xs:attribute-set>
<xs:attribute-set name="tableStyle">
<xs:attribute name="border">solid 0.1mm black</xs:attribute>
<xs:attribute name="text-align">center</xs:attribute>
</xs:attribute-set>
<xs:attribute-set name="tableHeaderStyle">
<xs:attribute name="border">solid 0.1mm black</xs:attribute>
<xs:attribute name="text-align">center</xs:attribute>
<xs:attribute name="font-weight">bold</xs:attribute>
</xs:attribute-set>
<xs:attribute-set name="stripedDesign">
<xs:attribute name="background-color">#123FC2</xs:attribute>
</xs:attribute-set>
</xs:stylesheet>
I removed the fo-templates because they are pretty big and compile without problems (apache-fop).
I've checked my XPath, it should work perfectly to get '#86f442'. Still, the XPath selector returns 0 nodes all the time and is null...
The document contains the xml though.
I am thankful for anyone whos helping.
//edit:
I also tried to directly select '//xs:attribute-set' instead of the more specific xpath selector. Still only returns an empty nodelist.
Same happens when I use
String node = expr.evaluate(doc);
with
//xs:attribute-set[#name =
\"tableImportantLine\"]/xs:attribute/text()
which returns null..
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.
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'm trying to validate a simple XML file against an XML schema using the following chunk of code. I'm getting an exception
org.xml.sax.SAXParseException: cvc-elt.1:
Cannot find the declaration of element 'Applications'
and was wondering if anyone had any idea why that could be. (When I try looking at what the contents of the schema are after it is loaded, I see a bunch of grammar objects or something of that sort, with nothing indicating that the schema is loaded properly. Could that be it? If I try loading a schema with an non-existing file name, it gives me a file not found exception...so I'm getting it is finding the right schema when the right file name is given)
public void getPriceSummaryInfo(){
Document doc = null;
try {
File fXmlFile = new File("testXML.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
doc = dBuilder.parse(fXmlFile);
}
catch (Exception e) {
e.printStackTrace();
}
try {
Schema schema = getSchema("testSchema.xsd");
Validator validator = schema.newValidator();
validator.validate(new DOMSource(doc));
}
catch (Exception e) {
e.printStackTrace();
}
}
private Schema getSchema (String xsdPath) throws Exception {
assert xsdPath != null : "XML schema path is null.";
SchemaFactory fact =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema;
try {
schema = fact.newSchema(new StreamSource(new File(xsdPath)));
}
catch (SAXException e) {
throw new Exception(
"Unable to find target schema to validate XML.", e);
}
return schema;
}
The xml and xsd files are:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.randomthing.com"
xmlns="http://www.randomthing.com"
elementFormDefault="qualified">
<xsd:element name="Applications">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="Application" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Application">
<xsd:annotation>
<xsd:documentation>
blah
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:long" use="required"/>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="order" type="xsd:long" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<?xml version="1.0" encoding="UTF-8"?>
<Applications xmlns ="http://www.randomthing.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.randomthing.com testSchema.xsd">
<Application id="3" name="Blah" order="2">
</Application>
</Applications>
Would appreciate any pointers! Thanks
You should parse the document with namespaces, you are losing them at load time.
dbFactory.setNamespaceAware(true);
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