I want to view the below defined xml schema into my expected xml. Can anyone help me what to write in XSD. Thanks in advance.
XML SCHEMA:
<xs:element name="Animal">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="type" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
EXPECTED OUTPUT in XML: <Animal type="carnivore">Tiger</Animal>.
With a schema containing only the element you showed, you can generate the instance you want in Java using JAXB. I added some context to your example, and included a namespace. This is the full XML Schema file (I called it animals.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://animals"
targetNamespace="http://animals"
elementFormDefault="qualified">
<xs:element name="Animal">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="type" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
Using the xjc tool (XSD to Java Compiler) you can generate classes from XML Schemas. So you can simply run:
xjc animals.xsd
And it will generate these files
animals/Animal.java
animals/ObjectFactory.java
animals/package-info.java
Place these in your classpath. Now you can write a simple program where you can create instances using that class, and then serialize it to XML using a JAXB marshaller:
import animals.Animal;
import javax.xml.bind.*;
public class App {
public static void main(String[] args) throws JAXBException {
Animal tiger = new Animal();
tiger.setType("carnivore");
tiger.setValue("Tiger");
JAXBContext jaxbContext = JAXBContext.newInstance(Animal.class);
Marshaller m = jaxbContext.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(tiger, System.out);
}
}
The result will be printed to the console:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Animal xmlns="http://animals" type="carnivore">Tiger</Animal>
Related
I am writing an XSD file to automatically generate Java classes to parse an XML file like this:
<pipeline:Pipeline
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:pipeline="http://www.intershop.de/pipeline/2010"
name="ViewCheckoutReview" type="view"
>
<nodes xsi:type="pipeline:Text" nodeID="Text0"/>
</pipeline:Pipeline>
I'm having issues when unmarshalling the xsi:type attribute on the <nodes> element.
These are my XSD files:
schema0.xsd:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:pipeline="http://www.intershop.de/pipeline/2010"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://www.intershop.de/pipeline/2010"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:import schemaLocation="schema1.xsd" />
<xs:element name="Pipeline">
<xs:complexType>
<xs:sequence>
<xs:element ref="nodes" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
schema1.xsd:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<xs:element name="nodes">
<xs:complexType>
<xs:attribute name="nodeID" type="xs:string" use="required" />
<xs:attribute ref="xsi:type" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
When I execute xjc using these XSD I get this error:
[ant:jaxb] parsing a schema...
[ant:jaxb] [ERROR] src-resolve.4.2: Error resolving component 'xsi:type'. It was detected that 'xsi:type' is in namespace 'http://www.w3.org/2001/XMLSchema-instance', but components from this namespace are not referenceable from schema document 'file:/C:/Projects/test/xsd/schema1.xsd'. If this is the incorrect namespace, perhaps the prefix of 'xsi:type' needs to be changed. If this is the correct namespace, then an appropriate 'import' tag should be added to 'file:/C:/Projects/test/xsd/schema1.xsd'.
[ant:jaxb] line 12 of file:/C:/Projects/test/xsd/schema1.xsd
[ant:jaxb]
[ant:jaxb] [ERROR] src-resolve: Cannot resolve the name 'xsi:type' to a(n) 'attribute declaration' component.
[ant:jaxb] line 12 of file:/C:/Projects/test/xsd/schema1.xsd
[ant:jaxb]
[ant:jaxb] Failed to parse a schema.
I have found a possible solution here on StackOverflow, which consists in adding the namespace attribute in the #XmlAttribute annotation of the generated Java class' field:
#XmlAttribute(name = "type", required = true, namespace = "http://www.w3.org/2001/XMLSchema-instance")
protected String type;
and changing schema1.xsd like this:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
attributeFormDefault="unqualified"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<xs:element name="nodes">
<xs:complexType>
<xs:attribute name="nodeID" type="xs:string" use="required" />
<!-- 'type' attribute is not referenced anymore -->
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
This solution works but I don't like it, because I would need to change manually, every time I run xjc, the generated Java classes to add that namespace attribute.
What I would like instead is to put something in the XSD file (or in a XJB file maybe?) which adds that namespace attribute automatically when I run xjc.
If I don't add that namespace attribute on the #XmlAttribute annotation, value of type attribute is always null:
public static void main(String[] args) throws JAXBException
{
File xmlFile = new File("D:\\temp\\test.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Pipeline.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Pipeline pipeline = (Pipeline) unmarshaller.unmarshal(xmlFile);
Nodes node = pipeline.getNodes();
System.out.println(node.getType()); // prints null
}
I use Apache XmlSchema 2.2.1 to parse XSD schema. I has the following schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.example.com/aigu"
xmlns="http://www.example.com/aigu"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" jxb:version="2.0">
<xs:attribute name="label" type="xs:string" />
<xs:element name="object">
<xs:complexType>
<xs:attribute ref="label" form="unqualified"/>
</xs:complexType>
</xs:element>
</xs:schema>
The following code produces exception
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.xml.sax.InputSource;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
public class Aigu {
public static void main(String[] args) {
String schema = "HERE_IS_CONTENT_OF_SCHEMA";
XmlSchemaCollection collection = new XmlSchemaCollection();
collection.read(new InputSource(new ByteArrayInputStream(schema.getBytes(StandardCharsets.UTF_8))));
}
}
Stacktrace:
Exception in thread "main" java.lang.IllegalArgumentException: local part cannot be "null" when creating a QName
at javax.xml.namespace.QName.<init>(QName.java:244)
at javax.xml.namespace.QName.<init>(QName.java:188)
at org.apache.ws.commons.schema.utils.XmlSchemaNamedWithFormImpl.setName(XmlSchemaNamedWithFormImpl.java:117)
at org.apache.ws.commons.schema.utils.XmlSchemaNamedWithFormImpl.setForm(XmlSchemaNamedWithFormImpl.java:105)
at org.apache.ws.commons.schema.XmlSchemaAttribute.setForm(XmlSchemaAttribute.java:170)
at org.apache.ws.commons.schema.SchemaBuilder.handleAttribute(SchemaBuilder.java:959)
at org.apache.ws.commons.schema.SchemaBuilder.handleAttribute(SchemaBuilder.java:923)
at org.apache.ws.commons.schema.SchemaBuilder.handleComplexType(SchemaBuilder.java:307)
at org.apache.ws.commons.schema.SchemaBuilder.handleElement(SchemaBuilder.java:420)
at org.apache.ws.commons.schema.SchemaBuilder.handleSchemaElementChild(SchemaBuilder.java:1512)
at org.apache.ws.commons.schema.SchemaBuilder.handleXmlSchemaElement(SchemaBuilder.java:659)
at org.apache.ws.commons.schema.SchemaBuilder.build(SchemaBuilder.java:157)
at org.apache.ws.commons.schema.XmlSchemaCollection.read(XmlSchemaCollection.java:508)
at org.apache.ws.commons.schema.XmlSchemaCollection.read(XmlSchemaCollection.java:717)
at org.apache.ws.commons.schema.XmlSchemaCollection.read(XmlSchemaCollection.java:565)
at com.netcracker.mediation.transition.model.xmltojava.Aigu.main(Aigu.java:23)
Is it a bug in Apache code or my schema is invalid?
The attribute form cannot be used in an attribute use that has a ref (as constrained in point 3.2 in this paragraph of the XML Schema specification).
Also, since the target of the reference is a top-level attribute declaration in a schema with a target namespace, its form, if it were allowed to put it explicitly, would have to be qualified.
It may explain the error, as the trace seems to indicate that it happens there.
This would be the corrected schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.example.com/aigu"
xmlns="http://www.example.com/aigu"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" jxb:version="2.0">
<xs:attribute name="label" type="xs:string" />
<xs:element name="object">
<xs:complexType>
<xs:attribute ref="label"/>
</xs:complexType>
</xs:element>
</xs:schema>
I have a JAXB class, which has an element coming from another namespace. I would like to have an ANY element as well, which collects all the elements not described in the JAXB class. So I added a List<Object> annotated with the #XmlAnyElement.
I have generated an XSD from the JAXB class, but when I am validating I am getting an error: "cos-nonambig: "nb":b and WC[##other:""] (or elements from their substitution group) violate "Unique Particle Attribution". During validation against this schema, ambiguity would be created for those two particles."
The JAXB class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType
public class Foo {
#XmlElement
String a;
#XmlElement(namespace="nb")
Bar b;
#XmlAnyElement
List<Object> other;
}
The XSD generated by JAXB
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:ns1="nb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="nb" schemaLocation="schema1.xsd"/>
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="a" type="xs:string" minOccurs="0"/>
<xs:element ref="ns1:b" minOccurs="0"/>
<xs:any processContents="skip" namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="bar">
<xs:sequence>
<xs:element name="bid" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="nb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="schema2.xsd"/>
<xs:element name="b" type="bar"/>
</xs:schema>
How should I add the XmlAnyElement to pass the validation?
I'm trying to validate a simple XML using a simple XSD, but always get this error:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'linux'. One of '{linux}' is expected.
Why? The tag 'linux' is found and is one of {linux}!
java code:
public static void main(String[] args) {
try {
InputStream xml = new FileInputStream("data/test.xml");
InputStream xsd = new FileInputStream("data/test.xsd");
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new StreamSource(xsd));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(xml));
log.info("OK!");
} catch (Exception e) {
log.error(":(");
log.error(e.getMessage());
}
}
data/test.xml:
<?xml version="1.0" encoding="utf-8"?>
<so xmlns="http://test/">
<linux>
<debian>true</debian>
<fedora>true</fedora>
</linux>
</so>
data/test.xsd
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema targetNamespace="http://test/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="so">
<xs:complexType>
<xs:sequence>
<xs:element name="linux">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:any processContents="lax" maxOccurs="unbounded"/>
</xs:sequence></xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Because the schema does not specify elementFormDefault="qualified", the local element declaration of element "linux" is declaring an element in no namespace, but the instance has a linux element in namespace "http://test/". The error message is confusing because it fails to make clear that the problem is with the namespace.
Dudytz, your <xs:any /> is not correct. The document cannot be validated, because the validator needs to be instructed how to validate the document. If you don't want that, you can specifiy for the <xs:any> a processContents attribute. If you set this to "lax" or "skip", it will work.
In short: replace <xs:any> with <xs:any processContents="lax" />
Update: We have changed your XSD to a working version:
<xs:schema xmlns="http://test/" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://test/">
<xs:element name="so">
<xs:complexType>
<xs:sequence>
<xs:element ref="linux"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="linux">
<xs:complexType>
<xs:sequence>
<xs:any processContents="lax" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Question
How to eliminate auto-generated namespace prefix that appears on all elements and attributes when using JAXB marshalling
I've demonstrated my current XML output after marshalling and the expected output.
Details
I'm using the default JaxB implementation (Metro) provided with JDK 1.6 update 21.
My XSD file is shown below. I used xjc to generate the Java Classes for this XSD and I dont want to add/change any
annotations in the generated Java classes, so that I can continue to use xjc.
In the code, this is how I marshal....where I create MYJAVAOBJECTTREE using ObjectFactory etc..
JAXBContext jcDXD = JAXBContext.newInstance(MDASJ.class);
QName qn=new QName(XMLDataFormat.XML_ROOT_NAME);
marshallerDXD = jcDXD.createMarshaller();
marshallerDXD.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshallerDXD.setProperty(Marshaller.JAXB_ENCODING, "ISO-8859-1");
marshallerDXD.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.theronyx.com/mdasj/xmldata mdasj-data.xsd");
jaxbElementDXD = new JAXBElement<MDASJ>(qn, MDASJ.class, MYJAVAOBJECTTREE);
marshallerDXD.marshal(jaxbElementDXD, System.out);
XSD File
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.theronyx.com/mdasj/xmldata" xmlns="http://www.theronyx.com/mdasj/xmldata">
<!-- definition of attributes -->
<xs:attribute name="ID" type="xs:string"/>
<xs:attribute name="ComputerTime" type="xs:string"/>
<xs:attribute name="VarId" type="xs:string"/>
<xs:attribute name="Value" type="xs:string"/>
<xs:attribute name="DataType" type="xs:string"/>
<!-- definition of complex elements -->
<!-- DIH -->
<xs:element name="DIH">
<xs:complexType>
<xs:attribute ref="ID" use="required"/>
</xs:complexType>
</xs:element>
<!-- TimeStamp -->
<xs:element name="TimeStamp">
<xs:complexType>
<xs:attribute ref="ComputerTime" use="required"/>
</xs:complexType>
</xs:element>
<!-- Variable -->
<xs:element name="Variable">
<xs:complexType>
<xs:attribute ref="VarId" use="required"/>
<xs:attribute ref="Value" use="required"/>
<xs:attribute ref="DataType" />
</xs:complexType>
</xs:element>
<!-- Root Data Spec -->
<xs:element name="MDASJ">
<xs:complexType>
<xs:sequence>
<xs:element ref="DIH"/>
<xs:element ref="TimeStamp"/>
<xs:element ref="Variable" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute ref="ID" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
Current XML File Output
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<MDASJ ns1:ID="MDASJID" xsi:schemaLocation="http://www.theronyx.com/mdasj/xmldata mdasj-data.xsd" xmlns:ns1="http://www.theronyx.com/mdasj/xmldata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:DIH ns1:ID="servo1"/>
<ns1:Variable ns1:DataType="Numeric" ns1:Value="0.19830813342577691127388561653788201510906219482421875" ns1:VarId="key1"/>
<ns1:Variable ns1:DataType="Text" ns1:Value="-3815206174054821329" ns1:VarId="key2"/>
</MDASJ>
Desired XML File Output is
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<MDASJ ID="MDASJID" xsi:schemaLocation="http://www.theronyx.com/mdasj/xmldata mdasj-data.xsd" xmlns="http://www.theronyx.com/mdasj/xmldata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DIH ID="servo1"/>
<Variable DataType="Numeric" Value="0.19830813342577691127388561653788201510906219482421875" VarId="key1"/>
<Variable DataType="Text" Value="-3815206174054821329" VarId="key2"/>
</MDASJ>
You can use a NamespacePrefixMapper
marshallerDXD.setProperty("com.sun.xml.bind.namespacePrefixMapper",
myNsPrefixMapper);
to have control for the namespace prefixes:
public class MyNsPrefixMapper extends NamespacePrefixMapper
{
public String getPreferredPrefix(String uri, String suggest, boolean require)
{
if("http://www.theronyx.com/mdasj/xmldata".equals(uri) ){return "";}
return suggest;
}
public String[] getPreDeclaredNamespaceUris()
{
// String[] result = new String[1];
// result[0] = "http://www.theronyx.com/mdasj/xmldata";
return new String[0];
}
}
I've tested the marshalling with:
MDASJ xml = ....;
JAXBContext context = JAXBContext.newInstance(MDASJ.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_ENCODING, "ISO-8859-1");
m.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,
"http://www.theronyx.com/mdasj/xmldata mdasj-data.xsd");
m.setProperty("com.sun.xml.bind.namespacePrefixMapper",new MyPrefixMapper());
m.marshal(xml, System.out);
and this JAXB implementation:
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>