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.
Related
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.
Following up on this question XSLT: Copy child elements of a complex type only once, i have a problem using that template recursivlely.
Lets say i have a structure like that:
<complexType name="InvoiceType">
<xs:element name="AdressIn" type="AdressType"/>
<xs:element name="AdressOut" type="AdressType" />
<xs:element name="Partner" type="PartnerType" />
<xs:element name="Date" type="DateType"/>
</complexType>
<complexType name="AdressType">
<xs:element name="Person" type="PersonType"/>
<xs:element name="City" type="string" />
<xs:element name="Nr" type="int" />
</complexType>
<complexType name="PartnerType">
<xs:element name="Person" type="PersonType"/>
<xs:element name="Age" type="int"/>
</complexType>
<complexType name="PersonType">
<xs:element name="Name" type="string"/>
</complexType>
And this template:
<xsl:template match="xs:complexType" mode="copy">
<xsl:apply-templates select="/xs:schema/xs:complexType[#name=current()/xs:sequence/xs:element/#type]"
<xsl:copy-of copy-namespaces="no" select="."></xsl:copy-of>
</xsl:template>
I am trying to copy all referenced complexType with this template. My problem now is, PersonType
is referenced both by AdressType and PartnerType (see example). In my outputfile, this type is printed twice. (simplified example)
How can i work around that?
Thanx for any help!
What do you actually want to do?
(1) Display all the complex types in the schema document? (that's easy).
(2) Display all the global complex types that are actually referenced from somewhere?
You could do
select(//xs:complexType[#name = //xs:element/#type])
(It's not correct in the presence of namespaces, but neither is your original)
(3) Display a complex type the first time it's encountered in some kind of graph traversal, but not subsequently?
That's much harder and involves some fairly tough recursive coding.
Generally, accessing schema information from source XSD files is difficult; it gets harder the more you want to handle "any schema in the wild" rather than just a few schemas written in the way you would write them. It might be worth standing back and asking what the purpose of this exercise is.
Im trying to find information on how to post data to Magento 1.9 SOAP API using PAW / POSTMAN.
Most importantly Im trying to find out how to add filters into the requests
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:Magento">
<soapenv:Header/>
<soapenv:Body>
<urn:salesOrderList soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<sessionId xsi:type="xsd:string">alreadydefinedandworking</sessionId>
</urn:salesOrderList>
</soapenv:Body>
</soapenv:Envelope>
Im currently using Soap UI to do my tasks but im stuck on how to add filters into the SOAP packets so I can get data out of Magento.
Is there any location online with Gists for the basics on connecting to Magento using the XML packets? Or if anyone knows how to add the filter in for incremental_id that would be super nice of you
request nodes differ depending on what type of soap API you use in Magento.
There are:
Soap v1
Soap v2
WS-I
if you use the most compatible WSI mode - request param definition looks like this:
<xsd:element name="salesOrderListRequestParam">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="sessionId" type="xsd:string"/>
<xsd:element minOccurs="1" maxOccurs="1" name="filters" type="typens:filters"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
where filters ns is:
<xsd:complexType name="filters">
<xsd:sequence>
<xsd:element name="filter" type="typens:associativeArray" minOccurs="0"/>
<xsd:element name="complex_filter" type="typens:complexFilterArray" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
both values are array-objects with key value pairs.
For more info see the code in API Helper, method: parseFilters() and _parseComplexFilter if you use conditions in filter.
some example (Soap_v2):
<ns1:salesOrderListRequestParam>
<sessionId>your sesion id</sessionId>
<filters>
<filter>
<complexObjectArray>
<key>increment_id</key>
<value>12345</value>
</complexObjectArray>
</filter>
</filters>
</ns1:salesOrderListRequestParam>
Below is a snippet of my wsdl that I'm having an issue with.
This is working, but I'm getting a validation error.
src-resolve.4.2: Error resolving component 'soapenc:Array.' It was detected that 'soapenc:Array' is in namespace 'schemas.xmlsoap.org/soap/encoding/';, but components from this namespace are not referenceable from schema document.
I added this to definitions in my wsdl: xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
<xsd:complexType name="getSalesTaxInformation_Array">
<xsd:complexContent>
<xsd:restriction base="soapenc:Array">
<xsd:sequence>
<xsd:element name="productTax" type="tns:getSalesTaxInformation"
maxOccurs="unbounded" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
What does this error mean and how do I get rid of it?
After a bit of digging, I figured it out. The error went away after I added these inside my schema element.
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
<xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" />
I don't know where I found the solution, but here's some information about using the Array thing in the wsdl.
https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Fuse/6.0/html/Writing_WSDL_Contracts/files/WSDLDefiningArrays.html
This is my current configuration:
XSD
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://stock.com/schemas/services/stock"
xmlns:tns="http://stock.com/schemas/services/stock"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" targetNamespace="http://stock.com/schemas/services/stock">
<xsd:element name="Stock">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ticker" nillable="true" type="xsd:string"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="quotes" nillable="true" type="Quote"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="Quote">
........
</xsd:complexType>
.......
<xsd:element name="gethighBetaStockResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="stock" ref="Stock" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
WSDL
<?xml version="1.0" encoding="UTF-8"?><definitions targetNamespace="http://stock.com/schemas/services/stock/wsdl"
.....xmlns:external="http://stock.com/schemas/services/stock"
<import namespace="http://stock.com/schemas/services/stock" location="Stock.xsd" />
<message name="getStockQuoteResp">
<part name="parameters" element="external:getStockQuoteResponse" />
</message>
However,the moment ref="Stock" is changed to type="Stock",the wsdl2java starts giving
Type {http://stock.com/schemas/services/stock}Stock is referenced but not defined.
Somehow it seems a clash between wsdl and xsd imports - but I just cant resolve it.Help is appreciated.
You have a couple of problems here.
First, the XSD has an issue where an element is both named or referenced; in your case should be referenced.
Change:
<xsd:element name="stock" ref="Stock" minOccurs="1" maxOccurs="unbounded"/>
To:
<xsd:element name="stock" type="Stock" minOccurs="1" maxOccurs="unbounded"/>
And:
Remove the declaration of the global element Stock
Create a complex type declaration for a type named Stock
So:
<xsd:element name="Stock">
<xsd:complexType>
To:
<xsd:complexType name="Stock">
Make sure you fix the xml closing tags.
The second problem is that the correct way to reference an external XSD is to use XSD schema with import/include within a wsdl:types element. wsdl:import is reserved to referencing other WSDL files. More information is available by going through the WS-I specification, section WSDL and Schema Import. Based on WS-I, your case would be:
INCORRECT: (the way you showed it)
<?xml version="1.0" encoding="UTF-8"?>
<definitions targetNamespace="http://stock.com/schemas/services/stock/wsdl"
.....xmlns:external="http://stock.com/schemas/services/stock"
<import namespace="http://stock.com/schemas/services/stock" location="Stock.xsd" />
<message name="getStockQuoteResp">
<part name="parameters" element="external:getStockQuoteResponse" />
</message>
</definitions>
CORRECT:
<?xml version="1.0" encoding="UTF-8"?>
<definitions targetNamespace="http://stock.com/schemas/services/stock/wsdl"
.....xmlns:external="http://stock.com/schemas/services/stock"
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://stock.com/schemas/services/stock" schemaLocation="Stock.xsd" />
</schema>
</types>
<message name="getStockQuoteResp">
<part name="parameters" element="external:getStockQuoteResponse" />
</message>
</definitions>
SOME processors may support both syntaxes. The XSD you put out shows issues, make sure you first validate the XSD.
It would be better if you go the WS-I way when it comes to WSDL authoring.
Other issues may be related to the use of relative vs. absolute URIs in locating external content.
import vs. include
The primary purpose of an import is to import a namespace. A more common use of the XSD import statement is to import a namespace which appears in another file. You might be gathering the namespace information from the file, but don't forget that it's the namespace that you're importing, not the file (don't confuse an import statement with an include statement).
Another area of confusion is how to specify the location or path of the included .xsd file: An XSD import statement has an optional attribute named schemaLocation but it is not necessary if the namespace of the import statement is at the same location (in the same file) as the import statement itself.
When you do chose to use an external .xsd file for your WSDL, the schemaLocation attribute becomes necessary. Be very sure that the namespace you use in the import statement is the same as the targetNamespace of the schema you are importing. That is, all 3 occurrences must be identical:
WSDL:
xs:import namespace="urn:listing3" schemaLocation="listing3.xsd"/>
XSD:
<xsd:schema targetNamespace="urn:listing3"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Another approach to letting know the WSDL about the XSD is through Maven's pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xmlbeans-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-sources-xmlbeans</id>
<phase>generate-sources</phase>
<goals>
<goal>xmlbeans</goal>
</goals>
</execution>
</executions>
<version>2.3.3</version>
<inherited>true</inherited>
<configuration>
<schemaDirectory>${basedir}/src/main/xsd</schemaDirectory>
</configuration>
</plugin>
You can read more on this in this great IBM article. It has typos such as xsd:import instead of xs:import but otherwise it's fine.