I had an XML like this:
<members>
<member>
<name>john</name>
<properties>
<age>20</age>
<address>20</address>
</properties>
</member>
<member>
<name>kayla</name>
<properties>
<gender>female</gender>
<address>20</address>
</properties>
</member>
</members>
There will be several member nodes in here, they all share a <name> node and a properties node. However, the elements in the properties are different, either age+address or gender+address are valid choices.
I tried to write an XSD like this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="members" type="membersType"/>
<xs:complexType name="membersType">
<xs:sequence>
<xs:element type="memberType" name="member" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="memberType">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element type="propertiesType" name="properties"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="propertiesType">
<xs:sequence>
<xs:element type="xs:string" name="address"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="propertiesTypeA">
<xs:complexContent>
<xs:extension base="propertiesType">
<xs:sequence>
<xs:element type="xs:string" name="age" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="propertiesTypeB">
<xs:complexContent>
<xs:extension base="propertiesType">
<xs:sequence>
<xs:element type="xs:string" name="gender" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
I hope there can be something like polymorphism in here, but when I validate using JAXP, that doesn't work.
I also tried to use the group feature, but there's a same address element in the 2 groups, thus it's still not available.
So, how should I design the XSD?
Your Current XML Schema
With your XML Schema the way it is, your XML would need to look like the following:
<members xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<member>
<name>john</name>
<properties xsi:type="propertiesTypeA">
<address>20</address>
<age>20</age>
</properties>
</member>
<member>
<name>kayla</name>
<properties xsi:type="propertiesTypeB">
<address>20</address>
<gender>female</gender>
</properties>
</member>
</members>
Note the following things:
The inherited attributes need to appear first.
You need to use the xsi:type attribute to override the element type to be the subtype.
What You Probably Want
Specifying a "choice" in your XML Schema would probably be a better fit for you. You would no longer need the sub types.
<xs:complexType name="propertiesType">
<xs:sequence>
<xs:choice>
<xs:element type="xs:string" name="age"/>
<xs:element type="xs:string" name="gender"/>
</xs:choice>
<xs:element type="xs:string" name="address"/>
</xs:sequence>
</xs:complexType>
You can use like that below
<complexType name="MemberDTO">
<complexContent>
<extension base="tns:MemberEnumValueDTO">
<sequence />
</extension>
</complexContent>
</complexType>
<complexType name="MemberEnumValueDTO">
<sequence>
<element name="name" type="tns:NameEnumTextType" minOccurs="1"
maxOccurs="1" />
</sequence>
</complexType>
<simpleType name="NameEnumTextType">
<restriction base="string">
<enumeration value="john" />
<enumeration value="kayla" />
</restriction>
</simpleType>
Related
XML
<ns2:Response xmlns:ns2="http://test.com/" Id="122212">
<Infos size="1">
<Info>
<name>test</name>
</Info>
</Infos>
</ns2:Response>
Generated XSD
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<!-- XML Schema Generated from XML Document on Mon Feb 20 2017 23:20:03 GMT+0530 (India Standard Time) -->
<!-- with XmlGrid.net Free Online Service http://xmlgrid.net -->
<xs:element name="ns2:Response">
<xs:complexType>
<xs:sequence>
<xs:element name="Infos">
<xs:complexType>
<xs:sequence>
<xs:element name="Info">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="size" type="xs:int"></xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="xmlns:ns2" type="xs:string"></xs:attribute>
<xs:attribute name="Id" type="xs:int"></xs:attribute>
</xs:complexType>
</xs:element>
Error
SAX Exception: s4s-att-invalid-value: Invalid attribute value for
'name' in element 'element'. Recorded reason:
cvc-datatype-valid.1.2.1: 'ns2:Response' is not a valid value for
'NCName'.
There are several changes required for your XML and XSD, including:
Change <xs:element name="ns2:Response"> to <xs:element
name="Response"> because element name declarations must be
non-colonized names (NCNAMEs).
Delete <xs:attribute name="xmlns:ns2".../> because namespaces
cannot be declared as attributes.
Add a targetNamespace to the XSD that matches the namespace of the root element in the XML document.
Import a separate XSD for those elements that you wish to be in no namespace (given that your root elements is in a namespace). You must use a separate XSD to accomplish this.
Altogether, your XML,
<?xml version="1.0" encoding="UTF-8"?>
<ns2:Response xmlns:ns2="http://test.com/"
Id="122212">
<Infos size="1">
<Info>
<name>test</name>
</Info>
</Infos>
</ns2:Response>
will validate successfully against these XSD:
Main
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
xmlns:ns="http://test.com/"
targetNamespace="http://test.com/">
<xs:import schemaLocation="Infos.xsd"/>
<xs:element name="Response">
<xs:complexType>
<xs:sequence>
<xs:element ref="Infos"/>
</xs:sequence>
<xs:attribute name="Id" type="xs:int"></xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
Imported (Infos.xsd)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Infos">
<xs:complexType>
<xs:sequence>
<xs:element name="Info">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="size" type="xs:int"></xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
I was able to get a parsed file by, as the above answer suggests, adding a target namepsace to the schema and by adding the ns prefix to all elements.
<?xml version="1.0" encoding="UTF-8"?>
<ns2:Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://test.com testq1.xsd" xmlns:ns2="http://test.com" Id="122212">
<ns2:Infos size="1">
<ns2:Info>
<ns2:name>test</ns2:name>
</ns2:Info>
</ns2:Infos>
and the schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test.com"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="Response">
<xs:complexType>
<xs:sequence>
<xs:element name="Infos">
<xs:complexType>
<xs:sequence>
<xs:element name="Info">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="size" type="xs:int"></xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Id" type="xs:int"></xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
You can approach this in 2 ways.
Approach 1 - multiple schemas
The more typical approach is to have a schema one for each namespace used.
So you end up with schemas that look like this
SampleXml0.xsd
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Studio 2017 (https://www.liquid-technologies.com) -->
<xs:schema xmlns:ns2="http://test.com/" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://test.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="C:\Temp\StackOverflow\42351409\SampleXml1.xsd" />
<xs:element name="Response">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" ref="Infos" />
</xs:sequence>
<xs:attribute name="Id" type="xs:unsignedInt" use="optional" />
</xs:complexType>
</xs:element>
</xs:schema>
SampleXml1.xsd
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Studio 2017 (https://www.liquid-technologies.com) -->
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Infos">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="Info">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="name" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="size" type="xs:unsignedByte" use="optional" />
</xs:complexType>
</xs:element>
</xs:schema>
Approach 2 - changing elementFormDefault
Now this is quite specific to your example, but as its only the root element that is qualified with a namespace its possible to change elementFormDefault to unqualified. This has the effect of forcing the elements defined as root element in the schema to have a namespace qualification, while the other elements do not.
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid Studio 2017 (https://www.liquid-technologies.com)-->
<xs:schema xmlns:ns2="http://test.com/" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://test.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Response">
<xs:complexType>
<xs:sequence>
<xs:element name="Infos" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="Info" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="size" type="xs:unsignedByte" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Id" type="xs:unsignedInt" use="optional" />
</xs:complexType>
</xs:element>
</xs:schema>
I would probably recommend creating multiple schemas as elementformdefault is typically overlooked by client implementations and ignored.
Why three <xs:sequence> elements? do you really need that? Could you explain better how your code is organized? Usually it is pretty simple, like this:
<xsd:element name="ns2:Response">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xs:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Below is my Schema.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:ns1="http://www.example.org/address" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="http://www.example.org/address" schemaLocation="www.example.org_address.xsd"/>
<xs:element name="dependant" type="dependant"/>
<xs:element name="employee" type="employee"/>
<xs:complexType name="employee">
<xs:sequence>
<xs:element name="dependantVO" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element ref="dependant" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="address" type="ns1:address" minOccurs="0"/>
<xs:element name="dob" type="xs:dateTime" minOccurs="0"/>
<xs:element name="joiningBonus" type="xs:decimal" minOccurs="0"/>
<xs:element name="name" type="xs:string" minOccurs="0"/>
<xs:element name="permanent" type="xs:boolean"/>
<xs:element name="role" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="id" type="xs:int" use="required"/>
</xs:complexType>
<xs:complexType name="dependant">
<xs:sequence>
<xs:element name="name" type="xs:string" minOccurs="0"/>
<xs:element name="relation" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Below is my address.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="http://www.example.org/address" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="address">
<xs:sequence>
<xs:element name="addressLine1" type="xs:string" minOccurs="0"/>
<xs:element name="addressLine2" type="xs:string" minOccurs="0"/>
<xs:element name="city" type="xs:string" minOccurs="0"/>
<xs:element name="zip" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
Now if i marshal the object "Employee" below is the generated employee.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee id="12">
<dependantVO>
<dependant>
<name>Vin Diesel</name>
<relation>Friend</relation>
</dependant>
<dependant>
<name>Black Ryan</name>
<relation>GF</relation>
</dependant>
</dependantVO>
<address>
<addressLine1>My Company</addressLine1>
<addressLine2>bangalore east</addressLine2>
<city>Bangalore</city>
<zip>560549</zip>
</address>
<dob>2015-07-28T10:04:34.599+05:30</dob>
<joiningBonus>10234.35467000000062398612499237060546875</joiningBonus>
<name>Paul Walker</name>
<permanent>true</permanent>
<role>SE</role>
</employee>
I have a problem of ordering the xml tags. Eg: Suppose i want addressline1 to be generated inside "employee" tag and outside "address" tag, also dependant name to be generated inside "employee" tag and outside "dependantVO" and "dependant" tag. Below is the xml that should be generated after the schema change
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee id="12">
<addressLine1>My Company</addressLine1>
<city>Bangalore</city>
<dependantVO>
<dependant>
<name>Vin Diesel</name>
<relation>Friend</relation>
</dependant>
<dependant>
<name>Black Ryan</name>
<relation>GF</relation>
</dependant>
</dependantVO>
<address>
<addressLine2>bangalore east</addressLine2>
<zip>560549</zip>
</address>
<dob>2015-07-28T10:04:34.599+05:30</dob>
<joiningBonus>10234.35467000000062398612499237060546875</joiningBonus>
<name>Paul Walker</name>
<permanent>true</permanent>
<role>SE</role>
</employee>
Note the addressLine1 tag and city tag is out of address tag and created inside employee tag. This is required because some of the common information are to be accessed easy from the generated xml. If someone tried this case or already done it, please help me out...
Sample XML response from REST WS -
<UserInfoDataContract xmlns="http://schemas.datacontract.org/2004/07/Interzoic.SSO.Shared" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<DisplayName>Test User</DisplayName>
<Email>test#test.com</Email>
<FirstName>Test</FirstName>
<IsSuperUser>false</IsSuperUser>
<LastName>User</LastName>
<Password>testuser1</Password>
<PortalID>0</PortalID>
<Roles xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:string>Registered Users</a:string>
</Roles>
<UserID>43</UserID>
<Username>testuser</Username>
</UserInfoDataContract>
XSD generated using http://xmlgrid.net/xml2xsd.html
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<!-- XML Schema Generated from XML Document on Thu Apr 09 2015 11:18:33 GMT-0500 (CDT) -->
<!-- with XmlGrid.net Free Online Service http://xmlgrid.net -->
<xs:element name="UserInfoDataContract">
<xs:complexType>
<xs:sequence>
<xs:element name="DisplayName" type="xs:string"></xs:element>
<xs:element name="Email" type="xs:string"></xs:element>
<xs:element name="FirstName" type="xs:string"></xs:element>
<xs:element name="IsSuperUser" type="xs:string"></xs:element>
<xs:element name="LastName" type="xs:string"></xs:element>
<xs:element name="Password" type="xs:string"></xs:element>
<xs:element name="PortalID" type="xs:int"></xs:element>
<xs:element name="Roles">
<xs:complexType>
<xs:sequence>
<xs:element name="a:string" type="xs:string"></xs:element>
</xs:sequence>
<xs:attribute name="xmlns:a" type="xs:string"></xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="UserID" type="xs:int"></xs:element>
<xs:element name="Username" type="xs:string"></xs:element>
</xs:sequence>
<xs:attribute name="xmlns" type="xs:string"></xs:attribute>
<xs:attribute name="xmlns:i" type="xs:string"></xs:attribute>
</xs:complexType>
</xs:element>
When i try to create JAXB Classes from the above XSD in eclipse, it gives me errors related to
<xs:attribute name="xmlns" type="xs:string"></xs:attribute>
<xs:attribute name="xmlns:i" type="xs:string"></xs:attribute>
and
<xs:attribute name="xmlns:a" in Roles element
and
<xs:element name="a:string" type="xs:string"></xs:element>
So i removed them and added
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.datacontract.org/2004/07/Interzoic.SSO.Shared" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" targetNamespace="http://www.w3.org/2001/XMLSchema-instance" elementFormDefault="qualified" attributeFormDefault="unqualified">
on the top.
How will the "Roles" from my XML be referenced in the XSD so that i can create a correct POJO class?
Taking reference from http://www.w3.org/TR/xmlschema-0/#ListDt, lists should be declared this way
<xsd:simpleType name="listOfMyIntType">
<xsd:list itemType="myInteger"/>
</xsd:simpleType>
I am not able to figure out how i can apply this to my XSD. Any help will be appreciated.
I think in xml in
<Roles xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
the xmlns:a
is considered as attribute by the ide that generates xsd, that's why in generated schema you have
<xs:attribute name="xmlns" type="xs:string"></xs:attribute>
So I agree with deleting
<xs:attribute name="xmlns:a" type="xs:string"></xs:attribute>
<xs:attribute name="xmlns" type="xs:string"></xs:attribute>
<xs:attribute name="xmlns:i" type="xs:string"></xs:attribute>
from xsd.
My only guess is try setting
targetNamespace="http://schemas.datacontract.org/2004/07/Interzoic.SSO.Shared"
as it is used explicitly in your xml
My transaction xml is shown below
<?xml version= "1.0"?>
<transactionlist>
<transaction action="c">
<transactionid>t004</transactionid>
<transactiondate>11/06/2013</transactiondate>
<merchantdetails>Sony wholesale Dealer</merchantdetails>
<itempurchased>3</itempurchased>
<amount>40399</amount>
<description>sony laptops</description>
</transaction>
<transaction action="d">
<transactionid>t003</transactionid>
</transaction>
<transaction action="u">
<transactionid>T001</transactionid>
<transactiondate>20/08/2013</transactiondate>
<merchantdetails>samsung Axses</merchantdetails>
<itempurchased>1</itempurchased>
<amount>40000</amount>
<description>samsung smart phone</description>
</transaction>
</transactionlist>
I have parsed the element itempurchased in above xml and stored it in integer variable. How to validate itempurchased only for numbers. that is i want to check whether itempurchased is number. pls provide suggestions
the best way should be validate xml against an xsd, where itempurchased would be of type xsd:int
below the xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="transactionlist">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="transaction">
<xs:complexType>
<xs:sequence>
<xs:element name="transactionid" type="xs:string" />
<xs:element minOccurs="0" name="transactiondate" type="xs:string" />
<xs:element minOccurs="0" name="merchantdetails" type="xs:string" />
<xs:element minOccurs="0" name="itempurchased" type="xs:int" />
<xs:element minOccurs="0" name="amount" type="xs:int" />
<xs:element minOccurs="0" name="description" type="xs:string" />
</xs:sequence>
<xs:attribute name="action" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Here Validating XML against XSD the code for validate xml against xsd
If you are marshaling your xml to a java bean then you may try using the Java6 Bean Validation Framework. Read more about it here:
http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html
It is as simple as putting an annotation on your bean:
public class MyXMLBean {
#Max(10)
#Min(5)
private int itempurchased;
}
The above bean will allow setting the value of itempurchased between min and max values mentioned in the annotations.
I make xml file using Jaxb from a xml schema my existing xml file looks like
<transaction>
<id>
<in>computer</in>
<sn>1234567</sn>
<book>JAVA</book>
<author>klen</author>
</id>
<data>
<dateTime>2011-06-24T17:08:36.3727674+05:30</dateTime>
<key>Err</key>
</data>
</transaction>
but I want to add inline schema before <id> node
My schema is looking like
<xs:schema id="transaction" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="transaction" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="id">
<xs:complexType>
<xs:sequence>
<xs:element name="in" type="xs:string" minOccurs="0" />
<xs:element name="sn" type="xs:string" minOccurs="0" />
<xs:element name="book" type="xs:string" minOccurs="0" />
<xs:element name="author" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="data">
<xs:complexType>
<xs:sequence>
<xs:element name="dateTime" type="xs:dateTime" minOccurs="0" />
<xs:element name="key" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="productData">
<xs:complexType>
<xs:sequence>
<xs:element name="dateTime" type="xs:dateTime" minOccurs="0" />
<xs:element name="key" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
now I want to add this before node under node.
Is it possible using Jaxb in first time?I cannot generate xml file with inline schema using jaxb.Due to the large size of my xml I cannot do this using Dom parser.Presently I try that at first generate xml file with data using jaxb and then rewrite the xml file and add schema under <transaction> node before <id> node.
I will prefer sun provided api.I am new in java so if some codesnips will be added it will be help full for me.