XML Binding Development Guide : PART III Advanced Topics : Chapter 8 Mapping XML Schema to C++ : Names and Identifiers
Names and Identifiers
HydraExpress follows the process below to convert XML names to C++ identifiers.
XML names can contain punctuation that is not allowed in a C++ identifier. HydraExpress replaces any character that cannot be used as a C++ identifier with the _ (underscore) character.
If the first character of the name for a complex type starts with a lower case letter, the code generator capitalizes the letter for the C++ class name.
For any constant that identifies the XML name for use by the marshal and unmarshal methods, the code generator capitalizes the first character and appends a suffix that identifies the purpose of the constant.
For any complex XML element that is a child of another element, named type, or named model group, the parent name is prepended to the XML element or type name to make the C++ class name. This prevents conflicts in naming when elements with the same name appear under two distinct parent structures. Here are some examples:
An element within a parent element, such as:
<element name="foo">
<complexType>
<sequence>
<element name="bar">
<complexType>...</complexType>
</element>
HydraExpress would generate two classes, Foo, and FooBar.
An element within a complex type, such as:
<complexType name="foo">
<sequence>
<element name="bar">
<complexType>...</complexType>
</element>
HydraExpress would generate two classes, Foo, and FooBar.
An element within a named model group, such as:
<group name="foo">
<sequence>
<element name="bar">
<complexType>...</complexType>
</element>
HydraExpress would generate just one class, FooBar, since model groups do not result in a generated class.
For a schema that contains a target namespace URI
that defines a namespace with a prefix to the target namespace URI, this prefix is used as the C++ namespace for the generated classes, and a separate directory is generated for each specified namespace. For example, in the schema element declaration below, the po prefix is associated with the URI that matches the value of the targetNamespace attribute, so the classes would be generated within the po namespace.
 
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:po="http://www.example.com/PO1"
targetNamespace="http://www.example.com/PO1">
that does not define a specific prefix, a C++ namespace is assigned using as a default the name of the schema file, and a separate directory is generated, as described above.
As part of its internationalization support, HydraExpress allows non-ASCII XML names. See “Internationalization” for details.
Naming collisions may still occur due to the way that HydraExpress maps XML names to C++. The code generator attempts to work around some of these naming collisions, but does not always find a satisfactory resolution.
If the code generator does not successfully resolve a naming collision, or if the resolution results in an inconvenient name, use the HydraExpress properties file mappings element to specify the class name mapping, as described in “Customizing Names and Identifiers”.
Static Data Members
The classes generated for complex types have these static data members:
the DefaultElementName data member
contained element name and attribute data members
The DefaultElementName Data Member
Each class generated by HydraExpress has a data member called DefaultElementName. This data member is an instance of rwsf::XmlName.
The DefaultElementName for a class is determined as follows:
For top-level elements, the DefaultElementName is the element name.
If the top-level element name would result in a file that conflicts with another file name in the default namespace, HydraExpress renames it elementnameElement.
For named complex types, the DefaultElementName is the complex type name.
For anonymous complex types, the DefaultElementName is the name of the containing element.
The marshal() and unmarshal() methods for a class use the DefaultElementName by default. This allows you to simply call marshal() or unmarshal() on a class, usually with good results. For example, if the schema defines a top-level element named purchaseOrder, the following code usually works as expected:
 
PurchaseOrder po;
po.marshal();
This code should produce, as expected, an XML document with a top-level element <purchaseOrder>.
There is one case, however, where the default use of the DefaultElementName does not work as you might expect:
 
<element name="foo" type="bar"/>
<complexType name="bar">
...
</complexType>
In this case, if the following code were used:
 
Bar b;
b.marshal();
the result would be an XML document containing a top-level element called <bar>, when it would make better sense for the name of the element to be <foo>. To obtain this better result, the second line above would need to be:
 
b.marshal("foo","schema_target_namespace");
Contained Element Name and Attribute Data Members
For each of the elements contained in a complex type, the class for the complex type has data members for the element names, and for any attributes of the complex type. The following code is taken from the XML Binding basic example:
 
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:element name="shipTo" type="USAddress"/>
<xsd:element name="billTo" type="USAddress"/>
<xsd:element ref="comment" minOccurs="0"/>
<xsd:element name="items" type="Items"/>
</xsd:sequence>
<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
The class PurchaseOrderType contains the following static data members:
 
static const rwsf::XmlName OrderDateAttributeName;
static const rwsf::XmlName ShipToElementName;
static const rwsf::XmlName BillToElementName;
static const rwsf::XmlName CommentElementName;
static const rwsf::XmlName ItemsElementName;
The names of the data members for the element names may not exactly match the names of the classes that represent them. They do not have parent names prepended, and may be different when substitution groups are used (see “Substitution Groups”).
Namespaces
There are two aspects to namespace support:
First, the generated marshaler and unmarshaler read and write namespace-qualified XML according to the schema definitions.
Second, HydraExpress uses namespaces to generate classes in a scope that is unique to the defined namespace.
For the former, HydraExpress passes rwsf::XmlName instances to the reader and writer for all fully qualified names. The header file for a complex type contains static constant rwsf::XmlName instances for the name of the complexType as well as any child elements and attributes that it defines. If the targetNamspace attribute on the XML Schema is present, this is the URI used for any namespace qualified structures:
Types are always namespace qualified.
Top-level elements (i.e., elements that occur directly under the schema declaration) are always namespace qualified.
Other elements are namespace qualified if either:
The element declaration in the schema defines the form attribute as qualified.
The element declaration does not define the form attribute, and the schema declaration defines the elementFormDefault attribute as qualified.
Attributes are namespace qualified if either:
The attribute declaration in the schema defines the form attribute as qualified.
The attribute declaration does not define the form attribute, and the schema declaration defines the attributeFormDefault attribute as qualified.
Otherwise, elements and attributes are not to be namespace qualified, and only the local name is used.
Accessing the Fully Qualified XML Name of a Complex Type
HydraExpress allows you to access the fully-qualified XML name of complex types. If a target namespace is present in the schema, the value is programmatically accessible using the DefaultElementName constant, as shown here:
 
aComplexType::DefaultElementName.getNamespace().getURI();
Mapping XML Namespaces to C++ Namespaces
If the schema contains a namespace declaration that associates a prefix to the target namespace URI, by default this prefix is used as the C++ namespace for the generated classes. In the example schema element declaration below, the po prefix is associated with the URI that matches the value of the targetNamespace attribute, so the classes would be generated within the po namespace.
 
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:po="http://www.example.com/PO1"
targetNamespace="http://www.example.com/PO1"
...
To use the generated classes you must prefix the type with the po namespace or make the name accessible with a using directive or using declaration. The following code snippets show both options.
Prefixing the type with a the po namespace:
 
// Code Example with C++ namespace qualified type name
int main() {
...
po::PurchaseOrderType order;
...
}
Importing all names in po with a using directive:
 
// Code Example with using directive
using namespace po;
 
int main() {
...
PurchaseOrderType order;
...
}
Importing po::PurchaseOrderType with a using declaration:
 
// Code Example with using declaration
using po::PurchaseOrderType;
 
int main() {
...
PurchaseOrderType order;
...
}
Instead of using the XML namespace prefix as the C++ namespace, you can choose your own C++ namespace through the use of the mappings element in a HydraExpress project file. The mapping element shown below instructs the code generator to generate the classes that are defined within the target namespace http://www.example.com/PO1, using the C++ namespace named POTypes.
 
<mappings>
<namespace uri="http://www.example.com/PO1" name="POTypes"/>
</mappings>
Differentiating Same-Named Items
It is entirely possible in an XML Schema to have two or more elements, types, or groups with the same name, so long as they are defined in separate namespaces. In this case, HydraExpress creates a separate class for each namespace-qualified item, placing the code for each class in a single pair of header and source files, named as usual with the unqualified name of the element, type or group.
Adding a Namespace to a Root Element
You can add a namespace to the root element without adding it to any children elements. To do so, use the addNamespaceDecl() function on rwsf::XmlStringWriter.
For example, the code below adds a namespace to the root element of myDocument:
 
#include <rwsf/core/XmlWriter.h> //1
#include <rwsf/core/XmlName.h>
#include <rwsf/core/XmlStringWriter.h>
#include <rwsf/core/XmlNamespace.h>
 
XmlStringWriter marshalWriter; //2
XmlNamespace qbNamespace("qb", "http://www.roguewave.com/Schema/Project"); //3
marshalWriter.addNamespaceDecl(qbNamespace); //4
myDocument.marshal( marshalWriter); //5
std::cout << "Marshal: " << marshalWriter.getString() << std::endl; //6
 
//1 Necessary includes.
//2 Creates a writer to marshal your object.
//3 Set the namespace with “qb” as the prefix and http://www.roguewave.com/Schema/Project as the URI.
//4 Invokes addNamespaceDecl() with the provided namespace.
//5 Marshals the object.
//6 Prints to standard out the marshaled XML document.
Once marshaled, the XML document contains the root namespace:
 
<?xml version="1.0" encoding="utf-8"?>
<my Document xmlns="http://www.roguewave.com/XMLSchema"
xmlns:qb="http://www.roguewave.com/Schema/Project">
...
</myDocument>
File Naming
As described in the remainder of this chapter, HydraExpress creates classes corresponding to top-level elements and complex types defined in the XML Schema. Generally, HydraExpress creates a header and a source file for each class, with the file name based on the unqualified name of the element or type. The exception is when multiple items have the same name but in different namespaces, as described above.
It is also possible for there to be name conflicts between elements, types, and groups in the same namespace. These are handled as follows:
If an element name conflicts with a type name, the generated class name remains the same; that is, it follows the standard naming conventions.
If a type name conflicts with an element name, the generated class for the type has the string Type appended to its name.
So, for example, if a schema defined an element named Address and a type named Address, HydraExpress would generate a class Address for the element and a class AddressType for the type.