Convert schema-aware stylesheet - xslt

I have a schema-aware XSLT transformation that works well. However, the anticipated users of the XSLT will likely not have access to a schema-aware processor. Thus, I'd like to write some code that will convert my schema-aware XSLT into an XSLT that can be used by basic level conforming processors.
For my purposes, the use of schema-aware constructs is limited to matching templates, i.e.
<xsl:template match="element(*, Candidate)">...</>
I'm not expecting this to be a fully automatic process. What I would like is to generate an XSLT that would, for every complexType in an XSD, find its use in a specified surfaced XSD element.
Example code:
<xsd:schema xmlns="example.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="example.xsd" elementFormDefault="qualified" version="0.0">
<xsd:element name="Candidate" type="Candidate"/>
<xsd:complexType name="Candidate">
<xsd:sequence>
<xsd:element name="Code" type="Code" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="Name" type="xsd:string" minOccurs="0"/>
<xsd:element name="PartyId" type="Code" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Code">
<xsd:sequence>
<xsd:element name="Value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
The expected output for the element Candidate would be something like this:
<complexType_usages>
<usage complexType="Code" path="Candidate/Code" />
<usage complexType="Code" path="Candidate/Party" />
</complexType_usages>

It might be simplest to work from a validated instance rather than trying to analyse the schema (so long as the instance is sufficiently representative). For every element, output the type annotation (using saxon:type-annotation) and the path, then take the list of type/path pairs, and eliminate duplicates and redundancy.

Related

How to remove unused namespaces from xsd using xslt. Keeping schema reference namespaces entact

I have an xsd file such as :-
<?xml version="1.0" encoding="UTF-8"?>
<xsd:element xmlns:ns2="http://www.tibco.com/ns/no_namespace_schema_location/UnitTest/TestProcess-End.xsd"
xmlns:ns="http://www.tibco.com/ns/no_namespace_schema_location/UnitTest/TestProcess-Map Data.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:pd="http://xmlns.tibco.com/bw/process/2003"
xmlns:ns="http://www.tibco.com/namespaces/tnt/plugins/jms"
name="group">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="root">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="a" type="xsd:string" minOccurs="0"/>
<xsd:element name="b" type="xsd:string" minOccurs="0"/>
<xsd:element name="c" type="xsd:string" minOccurs="0"/>
<xsd:element name="d" type="xsd:string" minOccurs="0"/>
<xsd:element name="e" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element ref="ns:root"/>
<xsd:element ref="ns2:root"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
This contains some un used namespaces, can any one explain how to achieve it with xslt:-
the output desired is :- Please note the namespaces which are used for schema references should be entact.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:element xmlns:ns2="http://www.tibco.com/ns/no_namespace_schema_location/UnitTest/TestProcess-End.xsd"
xmlns:ns="http://www.tibco.com/ns/no_namespace_schema_location/UnitTest/TestProcess-Map Data.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="group">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="root">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="a" type="xsd:string" minOccurs="0"/>
<xsd:element name="b" type="xsd:string" minOccurs="0"/>
<xsd:element name="c" type="xsd:string" minOccurs="0"/>
<xsd:element name="d" type="xsd:string" minOccurs="0"/>
<xsd:element name="e" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element ref="ns:root"/>
<xsd:element ref="ns2:root"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Use exclude-result-prefixes in xslt declaration
In XSLT 2.0, you can do <xsl:copy-of select="/" copy-namespaces="no"/> which will copy the entire document, excluding any namespaces that aren't used in element or attribute names. However, it might remove namespaces that are used only in attribute content, for example ref="ns2:root". Detecting those cases reliably is quite tricky, especially if they are used inside XPath expressions (e.g. in xs:key and xs:keyref constraints).
If you want to remove all "unused" namespaces except those in a $retain list, you could do something like (again XSLT 2.0):
<xsl:template match="*">
<xsl:copy copy-namespaces="no">
<xsl:copy-of select="#*"/>
<xsl:copy-of select="namespace::*[not(name()=$retain)]"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
and you could perhaps initialize $retain to contain all strings in the stylesheet that match [A-Za-z0-9]:, minus the colon.

XSLT stylesheet for creating an XML Schema Definition

My input data looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<ns1:queryResponse xmlns:ns1="http://abc.com/">
<ns1:result>
<ns1:records xmlns:ns2="http://def.com/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:Account">
<ns2:Id>2c</ns2:Id>
<ns2:Number>A722</ns2:AccountNumber>
</ns1:records>
</ns1:result>
</ns1:queryResponse>
I need to write a stylesheet which will create XML of the format:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="Account">
<xsd:sequence>
<xsd:element minOccurs="0" name="Id" type="xsd:string"/>
<xsd:element minOccurs="0" name="Number" type="xsd:string">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
The stylesheet should be able to create this XML?
The fields are also dynamically changing, so the stylesheet has to be generic so that it can extract the element name and value from the XML and create the output XML.

why am I getting Invalid attribute value for 'type' in element 'element' in my webservice?

I'm making a contract first webservice so my first xds(MensajeDetails.xds) is:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://webservices.samples.blog.com" targetNamespace="http://webservices.samples.blog.com" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="Mensaje" type="Mensaje"/>
<xs:complexType name="Mensaje">
<xs:sequence>
<xs:element name="IdMensajesEnviados" type="xs:long"/>
<xs:element name="CodigoEstatus" type="xs:int"/>
<xs:element name="DescripcionEstatus" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
and in my 2nd xds (MensajeDetailsServiceOperation.xds) I´ve:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://com/blog/samples/webservices/mensajeservice" xmlns:account="http://webservices.samples.blog.com" targetNamespace="http://com/blog/samples/webservices/mensajeservice" elementFormDefault="qualified">
<xsd:import namespace="http://webservices.samples.blog.com" schemaLocation="MensajeDetails.xsd"/>
<xsd:element name="MensajeDetailsRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="IdUsuario" type="xsd:long"/>
<xsd:element name="Token" type="xsd:string"/>
<xsd:element name="IdServicio" type="xsd:int"/>
<xsd:element name="Archivo" type="xsd:byte"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="MensajeDetailsResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="MensajeDetails" type="mensaje:Mensaje"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
So eclipse is telling me that in my 2nd xds
s4s-att-invalid-value: Invalid attribute value for 'type' in element 'element'.
Recorded reason: UndeclaredPrefix: Cannot resolve 'mensaje:Mensaje' as a QName: the prefix 'mensaje' is not declared." in the line:
<xsd:element name="MensajeDetails" type="mensaje:Mensaje"/>
What am I doing wrong?
You have imported the namespace into your schema and have declared a namespace prefix for it, in your schema declaration your have xmlns:account="http://webservices.samples.blog.com", this binds the prefix "account" to your imported namespace.
So, either change your element to account:Mensaje or change the prefix to mensaje
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://com/blog/samples/webservices/mensajeservice"
xmlns:mensaje="http://webservices.samples.blog.com"
targetNamespace="http://com/blog/samples/webservices/mensajeservice"
elementFormDefault="qualified">

xs:choice embedded in xs:sequence prevents the use of a union

I have the following xsd
<xsd:complexType name="myID">
<xsd:choice>
<xsd:element name="testID" type="priv:testID"/>
<xsd:sequence>
<xsd:element name="newID" type="priv:newID"/>
<xsd:element name="testID" type="priv:testID" minOccurs="0"/>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
Everything is under priv namespace. The problem is that it looks like that myID is a union. It might be a testID or a sequence with newID and testID. When I compile it with wsdl2h from gsoap I am taking the message:
Note: <xs:choice> with embedded
<xs:sequence> or <xs:group>
prevents the use of a union
Is the above XSD correct?
In general the XML type myID can be declared as you described. The conflict exist probably in connection with your definition of the types priv:testID and priv:testID which definition you not included. For example the schema
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema targetNamespace="http://www.ok-soft-gmbh.com/xml/xsd/1.0/XMLSchema.xsd"
elementFormDefault="qualified"
xmlns:priv="http://www.ok-soft-gmbh.com/xml/xsd/1.0/XMLSchema.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<xsd:simpleType name="testID">
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="newID">
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
<xsd:complexType name="myID">
<xsd:choice>
<xsd:element name="testID" type="priv:testID"/>
<xsd:sequence>
<xsd:element name="newID" type="priv:newID"/>
<xsd:element name="testID" type="priv:testID" minOccurs="0"/>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
<xsd:element name="root" type="priv:myID"/>
</xsd:schema>
will be correct. So if an error exist, it is not in the part which you posted.

Get default value for element from schema using xerces (C++)

Say I have a schema which defines an element as follows:
<xsd:element name="Widget" type="tns:WidgetType" />
<xsd:complexType name="WidgetType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:normalizedString" maxOccurs="1" minOccurs="1" />
<xsd:element name="Description" type="xsd:normalizedString" default="Unknown" maxOccurs="1" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
I'm parsing (DOM parser) an XML file that has been validated against this schema using Xerces-C++. If the Description element is present, I know how to read it by iterating through all the child elements of the DOMElement for a given Widget and using DOMElement::getTextContent() upon finding the Description element.
But, if a particular Widget element does not have a Description child element (which is allowed by the schema), how can I fetch the default value (Unknown) from the schema?
Thanks for your responses,
Ashish
You should be able to use XPath or XQuery to query the schema document to grab any values off of the schema document. Xerces site says it has partial XPath support, and lists Xalan and XQilla if you need more power.