I'm developing WebService with JAX-WS(i'm using wsimport goal on jaxws-maven-plugin). I wrote a WSDL that imports a XSD schema.
WEB-INF/wsdl/service.wsdl
WEB-INF/wsdl/service.xsd
Also I generated web service classes and created endpoint and all. Everything worked great so far. When I ran my service on Tomcat 7 everything is ok. I can access a wsdl in my browser from:
http://localhost:8080/webService/servlet-url?wsdl
but I cannot get access to a xsd schema. The problem is in this wsdl:
<xsd:schema>
<xsd:import namespace="http://ws.service/domain/1.0" schemaLocation="service.xsd"/>
</xsd:schema>
Of course during generation of classes wsdl and xsd are on local path but i want them to be remotely accessible when web service is running. I know that schemaLocation should be something like this "http://localhost:8080/webService/servlet-url?xsd=1".
In wsdl presented in browser import schould look like:
<xsd:schema>
<xsd:import namespace="http://ws.service/domain/1.0" schemaLocation="http://localhost:8080/webService/servlet-url?wsdl&resource=service.xsd"/>
</xsd:schema>
localhost:8080/webService/servlet?wsdl gives me:
wsdl:definitions targetNamespace="http://ws.serv.com/Service/1.0" name="emuiaService">
<wsdl:types>
<xsd:schema>
<xsd:import namespace="http://ws.serv.com/Service/domain/1.0" schemaLocation="schema.xsd"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="halloMsg">
<wsdl:part name="parameters" element="dom:halloRequest"/>
</wsdl:message>
<wsdl:message name="halloResponseMsg">
<wsdl:part name="return" element="dom:halloResponse"/>
</wsdl:message>
and so on...
I almost can't believe that this was such a difficult problem to solve!
I've been googling like mad to find a solution to exactly this problem! Then I've been struggling really hard to find a solution on my own. By debugger-stepping through the java-6-openjdk's default javax.xml.ws.spi.Provider implementation (the "factory" in the JRE that creates the javax.xml.ws.Endpoint objects that you use for publishing web services) I finally learnt some things, which helped me to craft a solution that at least works in Java SE, at least in my current JRE, which is:
java version "1.6.0_33"
OpenJDK Runtime Environment (IcedTea6 1.13.5) (6b33-1.13.5-1ubuntu0.12.04)
OpenJDK Server VM (build 23.25-b01, mixed mode)
Whether this solution is usable in Java EE I don't know yet.
Here is how I solved it:
package myservice;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Endpoint;
public class App
{
private static final String MY_SERVICE_XSD = "/wsdl/MyService.xsd";
public static void main( String[] args )
{
Endpoint ep = Endpoint.create(new MyEndpointImpl());
ep.setMetadata(Arrays.asList(sourceFromResource(MY_SERVICE_XSD)));
ep.publish("http://localhost:8080/svc/hello");
}
private static Source sourceFromResource(String name) {
URL resource = App.class.getResource(name);
String systemId = resource.toExternalForm();
InputStream inputStream;
try {
inputStream = resource.openStream();
} catch (IOException e) {
throw new RuntimeException("Failed to create InputStream from resource \""+ name +"\"", e);
}
return new StreamSource(inputStream, systemId);
}
}
The crucial thing is that I first use method Endpoint#create (not Endpoint#publish) to get an unpublished Endpoint. Then I add the XSD-file as "meta data" to the (still unpublished) Endpoint (code "ep.setMetaData(...)"). Then I publish the endpoint (code "ep.publish(...)").
Now when I access http://localhost:8080/svc/hello?wsdl I get:
<definitions targetNamespace="http://somewhere.net/my/namespace" name="MyService">
<types>
<xsd:schema>
<xsd:import namespace="http://somewhere.net/my/namespace"
schemaLocation="http://localhost:8080/svc/hello?xsd=1"/>
</xsd:schema>
</types>
...
</definitions>
and my XSD-file is available from http://localhost:8080/svc/hello?xsd=1!
Note that my MyService.wsdl file on disk still contains:
<xsd:schema>
<xsd:import namespace="http://somewhere.net/my/namespace"
schemaLocation="MyService.xsd"></xsd:import>
</xsd:schema>
Ok, here we go.
Into WSDL file to modificate something like this
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wsdl:definitions
targetNamespace="http://service.wsr.company.com/"
name="webServiceExample"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://servicio.wsr.baz.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
On this little snippet important are xmlns tag. Those serve for deployment of schema XSD. Next
<wsdl:types>
<xs:schema
xmlns:tns="http://service.wsr.company.com/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://service.wsr.company.com/" version="1.0">
...
</xs:schema>
</wsdl:types>
Into those tag below you'll get what you have in service.xsd file or show it in http://localhost:8080/webService/servlet-url?xsd=1 we continue
<wsdl:message name="your_method_name">
<wsdl:part name="parameters" element="tns:your_method_name"/>
</wsdl:message>
<wsdl:message name="your_method_nameResponse">
<wsdl:part name="parameters" element="tns:your_method_nameResponse"/>
</wsdl:message>
Those above tag are show your method name. Next
<wsdl:portType name="webServiceExample">
<wsdl:operation name="your_method_name">
<wsdl:input message="tns:your_method_name"/>
<wsdl:output message="tns:your_method_nameResponse"/>
</wsdl:operation>
</wsdl:portType>
Those above tar are for put your operation's. Continue
<wsdl:binding name="webServiceExamplePortBinding" type="tns:webServiceExample">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="your_method_name">
<soap:operation soapAction=""/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
Next one :)
<wsdl:service name="webServiceExample">
<wsdl:port name="webServiceExamplePort" binding="tns:webServiceExamplePortBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
</wsdl:port>
And finally finished :)
Note that you have to change the current tag by tag <wsdl:...></wsdl:...>
You save it, the public and you have fun XSD schema is presented in the WSDL.
I hope help you. Ciao.
Related
I am working on an application that uses XJC to generate Java POJOs from XSDs. There are dozens of schemas, and that number will grow. The application also needs to be able to handle different versions of the same schema, which means that I will have multiple schemas defining common types. I am trying to customize the bindings so that certain core types implement a common interface. The Inheritance plugin of JAXB2 Basics seems to do what I need, but I can't seem to nail the right syntax.
Here is the relevant part of my schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://example.com/core"
targetNamespace="http://example.com/core"
xmlns:xml="http://www.w3.org/XML/1998/namespace">
...
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="Address" type="xs:string"/>
<xs:element name="City" type="xs:string"/>
<xs:element name="Province" type="xs:string"/>
<xs:element name="Country" type="xs:string"/>
<xs:element name="County" type="xs:string" minOccurs="0"/>
<xs:element name="PostalCode" type="xs:string"/>
</xs:sequence>
</xs:complexType>
...
</xs:schema>
... and this is what my custom binding file looks like:
<?xml version="1.0"?>
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
xmlns:my="http://example.com/core"
jaxb:extensionBindingPrefixes="inheritance"
version="2.1">
<jaxb:bindings scd="x-schema::my" xmlns:my="http://example.com/core">
<jaxb:globalBindings localScoping="toplevel">
<jaxb:serializable/>
<xjc:simple/>
</jaxb:globalBindings>
<jaxb:bindings scd="/type::my:addressType">
<inheritance:implements>com.mysite.validator.ValidatableAddress</inheritance:implements>
<!--<xjc:superInterface name="com.mysite.validator.ValidatableAddress"/>-->
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
I'm using the scd approach, because in all the "traditional" binding examples that show how to use the inheritence plugin, schemaLocation is specified. I want to avoid having to specify schemaLocation because of our large (and growing) number of schemas. I don't want to have to change the binding file every time we add a new schema. So, scd seems like it will satisfy this requirement.
However when I run the build using the above binding, I get this:
[xjc] [ERROR] cvc-elt.1: Cannot find the declaration of element 'inheritance:implements'.
[xjc] line 18 of file:/dev/workspace/my_app/etc/schemas/bindings-common.xml
[xjc] failure in the XJC task. Use the Ant -verbose switch for more details
[xjc] classLoader = java.net.URLClassLoader#ebcdbb
[xjc] SharedSecrets.getJavaNetAccess()=java.net.URLClassLoader$7#14562c5
If I comment out the inheritance:implements line and uncomment the xjc:superInterface line, the error goes away and the build completes successfully, but my AddressType classes don't implement the ValidatableAddress type.
Can the inheritence plugin be used with scd? Can xjc:superInterface be limited to only certain elements?
Cheers.
Author of jaxb2-basics here.
See this issue in XJC. In short, XJC for some reason does not allow custom/vendor customization elements in SCD bindings.
inheritance:implements is such customization element.
So no, this does not work due a problem in XJC.
I personally bind via schemaLocation and XPath but use a "virtual" schema location URI and rewrite it via catalogs.
SCD would have been a much better choice (you're absolutely right here) but it just does not work.
Update on virtual schema location and catalogs.
Here's an example of binding which customizes some complex type:
<jaxb:bindings
schemaLocation="http://schemas.opengis.net/wps/2.0/wpsCommon.xsd"
node="/xs:schema">
<jaxb:bindings node="xs:element[#name='Data']/xs:complexType">
<wildcard:lax/>
</jaxb:bindings>
</jaxb:bindings>
It is bound via schemaLocation and XPath. The schemaLocation is an existing URL, but in the build it is rewritten via catalog into the resource inside a Maven artifact:
REWRITE_SYSTEM "http://schemas.opengis.net" "maven:org.jvnet.ogc:ogc-schemas:jar::!/ogc"
So basically http://schemas.opengis.net/wps/2.0/wpsCommon.xsd will be loaded from the ogc-schema.jar!/ogc/wps/2.0/wpsCommon.xsd.
Using maven-jaxb2-plugin you can refer to binding files inside Maven artifacts as well:
<binding>
<dependencyResource>
<groupId>${project.groupId}</groupId>
<artifactId>ows-v_2_0</artifactId>
<resource>ows-v_2_0.jsonix.xjb</resource>
<version>${project.version}</version>
</dependencyResource>
</binding>
So, in combination, it allows writing binding files once and reuse them across modules.
But this was all a huge pain to figure out. I did it for the ogc-schemas project which is now some 50 heavily interconnected schemas. I heavily suffer from XJC drawbacks and issues, but this is the best possible at the moment. I even thought about forking and patching XJC, but this is far of effort limits I can afford.
So I've ended up with a number of mindblogging workarounds which somehow do the job at the end of the day.
Thanks to lexicore for the prompt and detailed answers. However that approach wasn't working for me, so I ended up with the following solution...
Because I am using Ant to invoke XJC, I ended up leveraging Ant's <copy filtering="true"...> capabilities to dynamically generate the binding file.
Here is my binding "template" file (bindings-common.xml):
<?xml version="1.0"?>
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
xmlns:my="http://http://example.com/core"
jaxb:extensionBindingPrefixes="inheritance"
version="2.1">
<jaxb:bindings>
<jaxb:globalBindings localScoping="toplevel">
<jaxb:serializable/>
<xjc:simple/>
</jaxb:globalBindings>
</jaxb:bindings>
<jaxb:bindings
schemaLocation="#bindingSchema#"
node="/xs:schema">
<jaxb:bindings node="//xs:complexType[#name='addressType']">
<inheritance:implements>com.example.validator.ValidatableAddress</inheritance:implements>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Note this line:
<jaxb:bindings
schemaLocation="#bindingSchema#"
node="/xs:schema">
This variable will get populated by Ant for each of the schemas that I am processing:
<property name="jaxb.binding.template" value="../etc/form-schemas/bindings-common.xml"/>
<property name="jaxb.binding.file" value="${jaxb.src.dir}/bindings-common${schema.version}.xml"/>
<echo message="Filtering ${jaxb.binding.file} using template ${jaxb.binding.template}"/>
<copy file="${jaxb.binding.template}"
tofile="${jaxb.binding.file}"
filtering="true">
<filterset>
<filter token="bindingSchema" value="../../etc/form-schemas/${schema.version}/common.xsd"/>
</filterset>
</copy>
<xjc destdir="${jaxb.src.dir}"
extension="true"
schema="${schema.file}"
package="${package}"
binding="${jaxb.binding.file}">
<arg value="-episode"/>
<arg value="${jaxb.src.dir}/common${schema.version}.episode"/>
<arg line="-Xinheritance"/>
<!-- Plugins -->
<classpath>
<fileset dir="../build-libs/">
<!-- JAXB2 Basics library -->
<include name="jaxb2-basics-0.6.4.jar"/>
<!-- JAXB2 Basics library dependencies -->
<include name="jaxb2-basics-runtime-0.6.4.jar"/>
<include name="jaxb2-basics-tools-0.6.4.jar"/>
<include name="javaparser-1.0.8.jar"/>
<include name="commons-beanutils-*.jar"/>
<include name="commons-lang-*.jar"/>
<include name="commons-logging-*.jar"/>
</fileset>
</classpath>
</xjc>
</target>
Hopefully this will help future generations of JAXB victims.
We have a wsdl that we want to use in Mule studio. We generated the Java classes through the CXF component. There are a lot of elements in the schemas that are like this :
<xs:element minOccurs="0" name="SortIndex" nillable="true" type="xs:string"/>
In the generated Java classes, we get them as JAXBElement which is not really nice as it is hard to work with those in the DataMapper. I saw that this behavior can be overriden by providing jaxb bindings. However, this is how our wsdl looks now:
<wsdl:portType name="ILegacy">
<jaxws:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
wsdlLocation="src\main\resources\Legacy.wsdl"
xmlns="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<enableWrapperStyle>false</enableWrapperStyle>
<jaxb:globalBindings generateElementProperty="false"/>
</jaxws:bindings>
However, this doesnt change the generation of JAXBElements. Is there something wrong with this code?
Are you suing wsdl2java or xjc? or something else?
If you are using CXF wsdl2java or xjc pass in your binding file as a parameter to the command:
bindings123.xjb:
<jaxws:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
wsdlLocation="src\main\resources\Legacy.wsdl"
xmlns="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<enableWrapperStyle>false</enableWrapperStyle>
<jaxb:globalBindings generateElementProperty="false"/>
</jaxws:bindings>
then use -b to pass the bindings file to jaxb:
xjc schema1.xsd schema2.xsd schema3.xsd -b bindings123.xjb
There are two WSDLs which share some of schemas they use to define their datatypes. Here is an example of one of the WSDLs:
<wsdl:definitions
name="FooService"
targetNamespace="http://xmlns.my.org/services/FooService/v001"
xmlns:srv="http://xmlns.my.org/services/FooService/v001"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:fault="java:org.my.exception"
...
>
<wsdl:types>
<xsd:schema>
<xsd:import namespace="java:org.my.exception" schemaLocation="../xsd/common/BusinessException.xsd"/>
<xsd:import namespace="http://xmlns.my.org/services/FooServiceMessages/v001" schemaLocation="../xsd/fooservice/FooServiceMessages_v001.xsd"/>
</xsd:schema>
</wsdl:types>
...
<wsdl:message name="BusinessException">
<wsdl:part element="fault:BusinessException" name="BusinessException"/>
</wsdl:message>
...
<wsdl:portType name="IFooService">
<wsdl:operation name="getItems">
...
<wsdl:fault message="srv:BusinessException" name="BusinessException"/>
</wsdl:operation>
...
</wsdl:portType>
...
</wsdl:definitions>
BusinessException.xsd is one of the common schemes.
I'm trying to generate Java code by these WSDLs with wsimport. It would be reasonable to compile common schemas separately from WSDLd and then reuse classes derived from these schemas while compiling WSDLs. For this purpose I've generated a JAXB episode file along with common Java code:
<bindings version="2.1" xmlns="http://java.sun.com/xml/ns/jaxb">
<bindings scd="x-schema::tns" xmlns:tns="java:org.my.exception">
<schemaBindings map="false">
<package name="org.my.integration.dto.common"/>
</schemaBindings>
<bindings scd="~tns:BusinessException">
<class ref="org.my.integration.dto.common.BusinessException"/>
</bindings>
</bindings>
<bindings scd="x-schema::tns" xmlns:tns="http://xmlns.my.org/BaseIdentifiers/v001">
<schemaBindings map="false">
<package name="org.my.integration.dto.common"/>
</schemaBindings>
<bindings scd="~tns:EntityIdentifierListType">
<class ref="org.my.integration.dto.common.EntityIdentifierListType"/>
</bindings>
<bindings scd="~tns:...">
<class ref="..."/>
</bindings>
...
</bindings>
</bindings>
http://xmlns.my.org/BaseIdentifiers/v001 namespace is filled with another common schema that's imported in FooServiceMessages_v001.xsd (actually in a schema that's imported in a schema that's ... that's imported in FooServiceMessages_v001.xsd).
Here is a wsimport call which I use to generate Java code:
wsimport -B-XautoNameResolution -Xnocompile -s ./../java/ -verbose -b ./bindings/fooservice/jaxws-bindings.xml -b ./bindings/fooservice/jaxb-bindings.xml -b ./bindings/common/common.episode -keep ./wsdl/FooService_v001.wsdl
The following error occurs on this call:
[ERROR] Schema descriptor {java:org.my.exception}BusinessException in message part "BusinessException" is not defined and could not be bound to Java. ...
BTW if a binding for BusinessException.xsd is described in a plain external JAXB binding file (not in a episode file) all works fine. Looks like wsimport has some problems with handling episode files which describe bindings for schemes which are imported in WSDL directly.
Is there a way to use episode files with wsimport for schemes directly imported in WSDL (like BusinessException.xsd in my case)?
As https://github.com/javaee/jaxb-v2/issues/514 says it is impossible to generate sources for WSDL using JAXB episodes.
Sun/Oracle engineers unable to implement necessary enhancement for 11 years (2008-2019). And recently Oracle thrown sources to Eclipse project (October 2018).
I generate WSDL binding without episodes, as final step I remove packages from common schema. For Gradle it looks like:
wsimport {
wsdl = file("${project.rootDir}/wsdl/PingService.wsdl")
bindings = files(...)
}
task('afterWsimport', type: Delete) {
delete new File(file(wsimport.javaDir), "com/bla/schema")
delete new File(file(wsimport.javaDir), "com/foo")
}
wsimport.finalizedBy(afterWsimport)
It seems that this is some kind of bug or incorrect behavior of wsimport. wsdl2java tool from Apache CXF lacks this problem.
Is it possible to generate entities with Claendar type fields from xsd files? I am trying both xs:date and xs:dateTime but still getting XMLGregarionCalendar. I am using cxf-codegen-plugin and jaxb bninding.
Thanks.
Paul.
When you generate your objects you can use a JAXB binding file, as demonstrated in Example 7 of the cxf-codegen-plugin documentation. Depending on what type you want to use (Calendar, Date, etc.), you will need to specify an appropriate adapter. To use Calendar, JAXB provides the adapter javax.xml.bind.DatatypeConverter. To use it with dateTime, date, and time, the JAXB bindings file should be
<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings version="2.1"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
<jxb:globalBindings>
<!-- use Calendar instead of XMLGregorianCalendar -->
<jxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
printMethod="javax.xml.bind.DatatypeConverter.printDateTime"/>
<jxb:javaType name="java.util.Calendar" xmlType="xs:date"
parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
printMethod="javax.xml.bind.DatatypeConverter.printDate"/>
<jxb:javaType name="java.util.Calendar" xmlType="xs:time"
parseMethod="javax.xml.bind.DatatypeConverter.parseTime"
printMethod="javax.xml.bind.DatatypeConverter.printTime"/>
</jxb:globalBindings>
</jxb:bindings>
If you want to use Date instead, CXF provides org.apache.cxf.xjc.runtime.DataTypeAdapter in cxf-xjc-runtime.
Building on Patrick's answer, here is the XJC equivalent:
<jaxb:bindings version="2.1"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
<jaxb:globalBindings>
<!-- use Calendar Date instead of XMLGregorianCalendar -->
<jaxb:javaType name="java.util.Date" xmlType="xs:dateTime"
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime"
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime"/>
<jaxb:javaType name="java.util.Date" xmlType="xs:date"
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDate"
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDate"/>
<jaxb:javaType name="java.util.Date" xmlType="xs:time"
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseTime"
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printTime"/>
</jaxb:globalBindings>
</jaxb:bindings>
I'm creating a geopositioning application and we intent to use KML as our import/export data scructure.
We need to store extra information on field definitions, but I'm having trouble understant how to use KML SimpleFieldExtension (in fact my problem is understant XML Schema and validation).
The Google KML tutorial https://developers.google.com/kml/documentation/extendeddata doesn't teach how to do it.
I understand that SimpleFieldExtension is an abstract element and there is no concrect element in the KML specfication.
<element name="SimpleFieldExtension" abstract="true"/>
So I need to extend it and create my own, rigth?
I would like to do something like this:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Schema name="mySchemaName" id="mySchemaId">
<SimpleField type="xsd:int" name="myValue">
<displayName>MyValue</displayName>
<mySimpleFieldExtension>
<someExtraInfo>...</someExtraInfo>
<otherExtraInfo>...</otherExtraInfo>
</mySimpleFieldExtension>
</SimpleField>
</Schema>
<!-- Some placemarks with myValue fields -->
</Document>
</kml>
When I was trying to figure this out, I came with the impression that I need to create a .xsd file with my own mySimpleFieldExtension, and some how points the .kml file to it. But I'm not sure if that is the right path.
<element name="mySimpleFieldExtension" substitutionGroup="kml:SimpleFieldExtension"/>
Can some one give me an example? Thank you in advance.
I'm using http://www.kmlvalidator.com/ to check my files.
If you want to create SimpleFieldExtension elements and validate it then you will need to create an XML Schema (.xsd) and refer that file in your KML documents.
Example XML Schema with KML extension:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:kml="http://www.opengis.net/kml/2.2"
xmlns:ext="http://myextension"
targetNamespace="http://myextension"
elementFormDefault="qualified"
version="2.2.0">
<import namespace="http://www.opengis.net/kml/2.2"
schemaLocation="http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd" />
<element name="SimpleMetadata" type="ext:SimpleMetadataType"
substitutionGroup="kml:SimpleFieldExtension"/>
<complexType name="SimpleMetadataType" final="#all">
<sequence>
<element name="description" type="string"/>
<element name="observedProperty">
<complexType>
<simpleContent>
<extension base="string">
<attribute name="type" type="string" use="required"/>
</extension>
</simpleContent>
</complexType>
</element>
<any namespace="##other" processContents="lax" minOccurs="0"
maxOccurs="unbounded"/>
</sequence>
</complexType>
</schema>
Here's KML document:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ext="http://myextension"
xsi:schemaLocation="http://myextension ext.xsd
http://www.opengis.net/kml/2.2 http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd">
<Document>
<Schema id="SensorTypesId" name="SensorTypes">
<SimpleField name="model" type="string"/>
<SimpleField name="reason" type="string"/>
<SimpleField name="speed" type="double">
<ext:SimpleMetadata>
<ext:description>this is the true air speed of a given
aircraft in meters per second</ext:description>
<ext:observedProperty type="urn:ogc:def:phenomenon:OGC:speed" />
</ext:SimpleMetadata>
</SimpleField>
</Schema>
...
A proposed example of a SimpleFieldExtension and discussion can be found here.
Note that http://www.kmlvalidator.com/ checks the strict KML specification and doesn't check KML extensions such as Google's KML extensions so you won't be able to validate custom extensions either.
You can validate such a KML document using the XML Validator which is a standalone command-line validator.
You'll need to add the namespace definition in the XML Validator ns.map config file:
http://myextension=${XV_HOME}/schemas/ext.xsd
or absolute path like this:
http://myextension=C:/myPath/ext.xsd
Even though the SimpleFieldExtension is supported by the KML standard, adding a custom SimpleFieldExtension through a custom XML Schema requires more testing to verify it doesn't cause problems to applications using it especially if you plan to share your KML outside your organization. Applications like Google Earth will simply ignore your extensions so only use extensions when you absolutely must.