|
Related YoLinux Tutorials:
°C++ Info, links
°C++ String Class
°C++ STL vector, list
°C++ Log4cxx logging
°MS/Visual C++ Practices
°C++ Memory corruption and leaks
°YoLinux Tutorials Index
Free Information Technology Magazines and Document Downloads
Free Information Technology Software and Development Magazine Subscriptions and Document Downloads
|
| XmlBeansxx / XmlBeanscxx Description |
The XmlBeansxx program and process is a C++ code generation program driven by an XSD XML schema definition.
XmlBeansxx can read an XSD schema definition and auto-generate C++ classes to parse and access an XML file which meets the schema definition.
XmlBeansxx will generate C++ classes and library which can be compiled in or linked into your C++ program.
Prerequisites:
- autoconf and automake (or cmake)
- RHEL5 (autoconf: 2.59, automake: 1.9.6): yum install autoconf automake
- Ubuntu 8.10 (autoconf: 2.61, automake: 1.10): apt-get install autoconf automake
- libtool:
- RHEL5 (libtool: 1.5.22): yum install libtool
(So old it leads to problems! See pitfalls below)
- Ubuntu 8.10 (libtool: 2.2.4): apt-get install libtool
- gmp (http://swox.com/gmp/)
- RHEL5 (gmp 4.1.4): yum install gmp gmp-devel
- Ubuntu 8.10 (libgmpxx4 4.2.2, libgmp3-dev: 4.2.2): sudo apt-get install libgmpxx4 libgmp3-dev
- boost and boost-devel
- RHEL5 (boost: 1.33.1): yum install boost boost-devel
- Ubuntu 8.10 (libboost-dev: 1.34.1): sudo apt-get install libboost-dev
- xerces-c: See the YoLInux.com Xerces-C 2.7.0 tutorial (Note that XmlBeansxx 0.9.8 works with Xerces-C 2.7.0 and not Xerces-C 3.0.1.)
- RHEL5: Download source, compile and generate RPMs for installation: rpmbuild -ta xerces-c-2.7.0.tar.gz
(Use RPMs as they install to /usr - required as XmlBeansxx does not allow one to specify an alternate path for Xerces)
- Ubuntu: Compile from source and install to /usr
- Install Java (1.4.0+ including 1.6): (XmlBeans code generation requires Java and the Maven build tool is a Java program)
See the YoLinux Java installation tutorial
- Install Maven (untar Java jar files. Java program and thus platform independent)
(Called by XmlBeans configure script and Makefile)
- Download compiled Java program: http://maven.apache.org/download.html
- cd /opt
- wget http://apache.opensourceresources.org/maven/binaries/apache-maven-2.2.1-bin.tar.gz
- tar xzf apache-maven-2.2.1-bin.tar.gz
This creates /opt/apache-maven-2.2.1
- Configuration:
- Add path to shell environment: export PATH=$PATH:/opt/apache-maven-2.2.1/bin
This allows execution of the Maven build command mvn
- If using a proxy, edit /opt/apache-maven-2.2.1/conf/settings.xml
Set proxy: <proxies> <proxy> ...
- Add mvn to path: export PATH=$PATH:/opt/apache-maven-2.2.1/bin
Note: Maven will require an internet connection to download the appropriate plug-ins during operation.
Ubuntu/Debian Note: Maven can also be installed using apt-get: sudo apt-get install maven2
- Log4cxx is an optional prerequisite (Version 0.9.7)
See the YoLinux.com Log4cxx tutorial for
Red Hat Enterprise Linux 5 (RHEL5) prerequisites and build instructions.
Note that XmlBeansxx requires that Log4cxx be installed to /usr and is not recognised by the XmlBeans build in any other location such as /opt or /usr/local.
Build and install:
- Build and install Log4cxx to /usr
- tar xzf xmlbeansxx-0.9.8.tar.gz
- cd xmlbeansxx-0.9.8
- ./bootstrap
- ./configure --prefix=/usr --disable-log4cxx (or with log4cxx if you plan to use its' logging facility.)
Typically I would specify /opt or /usr/local but execution of xmlbeansxx scompxx command requires /usr in order to fuction. (As Far As I Can Tell)
- make
[Potential Pitfall]: RHEL5:
If you get the error (and you will):
-
../../libtool: line 466: CDPATH: command not found
../../libtool: line 1144: func_opt_split: command not found
This due to the file ./libtool which is created by ./configure is for
the newer version of libtool 2.2.4
while RHEL5 has libtool version 1.5.22 /usr/bin/libtool which does not have these functions.
Thus fix by:
- mv libtool NoGood-libtool
- ln -s /usr/bin/libtool ./
Then try make again.
Note Ubuntu 8.10 uses libtool 2.2.4 and does not have this problem.
- make check
This requires cppunit to be installed before executing "configure".
(Note: "CalendarTest" failed for me, the rest was Ok)
- make install
Installs to /usr/include/xmlbeansxx/, /usr/lib, /usr/bin and /usr/share/xmlbeansxx/ for configure "--preifix=/usr".
Links:
The first example is using a variation of the Apache XML Beans sample XSD and XML
The second is our own YoLinux.com example using a more complex XSD and XmlBeansxx compiled with Log4cxx.
| Apache XML Beans XSD example: |
The following schema example is based on the
Apache XML Beans example.
File: EasyPO.xsd
-
<!--
Copyright 2004 The Apache Software Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<xs:schema
targetNamespace="http://xmlbeans.apache.org/samples/enumeration/schemaenum/easypo"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:po="http://xmlbeans.apache.org/samples/enumeration/schemaenum/easypo"
elementFormDefault="qualified">
<xs:element name="purchase-order">
<xs:complexType>
<xs:sequence>
<xs:element name="customer" type="po:customer"/>
<xs:element name="date" type="xs:dateTime" />
<xs:element name="line-item" type="po:line-item" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="shipper" type="po:shipper" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="customer">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="line-item">
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="per-unit-ounces" type="xs:decimal"/>
<xs:element name="price" type="xs:double"/>
<xs:element name="quantity" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="shipper">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="per-ounce-rate" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
|
Note:
- The "xs:" prefix refers to XML built-in type definitions defined by the w3.org (World Wide Web consortium).
- The "po:" prefix refers to "Purchase Order" schema defined by the enumerations in http://xmlbeans.apache.org/samples/enumeration/schemaenum/easypo
Generate C++ classes from XSD: /usr/bin/scompxx EasyPO.xsd
File: testEasyPO.cpp
-
#include "EasyPO.h"
#include <iostream>
#include <fstream>
using namespace std;
using namespace xmlbeansxx;
using namespace xmlbeansxx::samples::enumeration::schemaenum::easypo;
int main() {
try {
fstream in("easypo.xml", ios::in);
PurchaseOrderDocument pDoc(PurchaseOrderDocument::Factory::parse(in));
xmlbeansxx::XmlOptions opts;
opts.setValidation(true);
vector<LineItem> arr = pDoc.getPurchaseOrder().getLineItemArray();
for(int i=0; i < arr.size() ; i++) {
cout << "item: " << i << endl;
cout << " - description: " << arr[i].getDescription() << endl;
cout << " - quantity: " << arr[i].getQuantity() << endl;
cout << " - price: " << arr[i].getPrice() << endl;
cout << " - amount: " << arr[i].getQuantity() * arr[i].getPrice() << endl;
}
// Debug line cout << "Xml:" << endl << pDoc.toString() << endl;
} catch (BeansException &ex) {
cout << "BeansException: " << ex.getMessage() << endl;
}
return 0;
}
|
Compile and link: g++ -g -o test testEasyPO.cpp src/EasyPO.cpp -Isrc/ -lxerces-c -lgmp -lgmpxx -pthread -lxmlbeansxx /usr/lib/libxmlbeansxx.a
(Static link)
File: easypo.xml
-
<?xml version="1.0" encoding="UTF-8"?>
<purchase-order
xmlns="http://xmlbeans.apache.org/samples/enumeration/schemaenum/easypo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<customer>
<name>Larry Kowalski</name>
<address>ul. Anytown, PA</address>
</customer>
<date>2005-01-01T12:00:00</date>
<line-item>
<description>Burnham's Celestial Handbook Vol 1</description>
<per-unit-ounces>10</per-unit-ounces>
<price>23</price>
<quantity>1</quantity>
</line-item>
<line-item>
<description>Burnham's Celestial Handbook Vol 2</description>
<per-unit-ounces>7</per-unit-ounces>
<price>22</price>
<quantity>1</quantity>
</line-item>
<line-item>
<description>Introduction to Linux</description>
<per-unit-ounces>7</per-unit-ounces>
<price>27</price>
<quantity>1</quantity>
</line-item>
<shipper>
<name>Zip Ship</name>
<per-ounce-rate>0.65</per-ounce-rate>
</shipper>
</purchase-order>
|
Test by running the resulting program: ./test
-
Locale: en_US.UTF-8
item: 0
- description: Burnham's Celestial Handbook Vol 1
- quantity: 1
- price: 23
- amount: 23
item: 1
- description: Burnham's Celestial Handbook Vol 2
- quantity: 1
- price: 22
- amount: 22
item: 2
- description: Introduction to Linux
- quantity: 1
- price: 27
- amount: 27
| A More Complex XSD example: |
XML Schema File: corporation.xsd
-
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="Corporation">
<xs:complexType>
<xs:sequence>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Phone" type="xs:string"/>
<xs:element name="Fax" type="xs:string"/>
<xs:element name="Address" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="People">
<xs:complexType>
<xs:sequence>
<xs:element name="Employee" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Name" type="xs:string"/>
<xs:choice>
<xs:element name="US-W2">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element name="EmpNumber" type="xs:int"/>
<xs:element name="Manager" type="xs:string"/>
<xs:element name="YearStart" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="US-1099">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element name="SsnNumber" type="xs:string"/>
<xs:element name="Phone" type="xs:string" default="1-800-555-1212"/>
<xs:element name="CorpName" type="xs:string"/>
<xs:element name="CorpAddress" type="xs:string"/>
<xs:element name="Relationship" type="ERelation"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
<xs:element name="Data">
<xs:annotation>
<xs:documentation>Data: personel data.</xs:documentation>
</xs:annotation>
<xs:complexType mixed="false">
<xs:sequence>
<xs:element name="WorkPhone" type="xs:string" default="1-800-555-1212"/>
<xs:element name="CellPhone" type="xs:string" default="1-800-555-1212"/>
<xs:element name="Address" type="xs:string" default="NULL"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="TaxStatus" type="ETaxStatus" use="required"/>
<xs:attribute name="Gender" type="EGender" use="required"/>
<xs:attribute name="Desc" type="ELocation" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="EGender">
<xs:restriction base="xs:string">
<xs:enumeration value="Male"/>
<xs:enumeration value="Female"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ELocation">
<xs:restriction base="xs:string">
<xs:enumeration value="OnSite"/>
<xs:enumeration value="OffSite"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ETaxStatus">
<xs:restriction base="xs:string">
<xs:enumeration value="US-W2"/>
<xs:enumeration value="US-1099"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ERelation">
<xs:restriction base="xs:string">
<xs:enumeration value="CorpToCorp"/>
<xs:enumeration value="CorpToIndividual"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
|
Note that XSD requires that element attributes are defined at the end of the element definition.
Generate C++ classes from XSD: /usr/bin/scompxx corporation.xsd
This will generate the files src/corporation.h and src/corporation.cpp
This is a hand cleanup script for all of the extra files you probably will not need:
rm -Rf config.h.in stamp-h1 config.log config.h Makefile config.status libtool configure
rm -Rf Makefile.in config autom4te.cache aclocal.m4 bootstrap configure.ac m4 Makefile.am
rm src/*.o src/xmltypes src/xsd.txt src/Makefile.am src/Makefile.in src/Makefile
rm -Rf src/*.lo src/libxmltypes.la src/xmltypes_headers.h src/.deps src/.libs
|
File: testProgramMain.cpp
-
#include "corporation.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <log4cxx/logger.h>
#include <log4cxx/xml/domconfigurator.h>
using namespace std;
using namespace xmlbeansxx;
using namespace log4cxx;
using namespace log4cxx::xml;
using namespace log4cxx::helpers;
LoggerPtr testProgramMain(log4cxx::Logger::getLogger("TestProgramMain"));
int main() {
DOMConfigurator::configure("Log4cxxConfig.xml"); // XMLBeans initialization
try {
fstream xmlData("CorporationMegaX.xml", ios::in);
noNamespace::RootDocument_Root *pDoc = new noNamespace::RootDocument_Root(noNamespace::RootDocument_Root::Factory::parse(xmlData));
xmlbeansxx::XmlOptions opts;
opts.setValidation(true);
cout << "Corporation Name: " << pDoc->getCorporation().getName() << endl;
cout << "Corporation Address: " << pDoc->getCorporation().getAddress() << endl << endl;
// Load "Employee" data into STL vector
vector<noNamespace::RootDocument_Root_People_Employee> arr = pDoc->getPeople().getEmployeeArray();
// For each "Employee", get tax info and data info.
for(int i=0; i < arr.size() ; i++)
{
cout << "Employee name: " << arr[i].getName() << endl;
switch (arr[i].getTaxStatus())
{
case 0: // US-W2
cout << " Employee number: " << arr[i].getUSW2().getEmpNumber() << endl;
break;
case 1: // US-1099
cout << " Employee SSN number: " << arr[i].getUS1099().getSsnNumber() << endl;
break;
default:
break;
}
cout << " Work phone: " << arr[i].getData().getWorkPhone() << endl;
}
// Debug line cout << "Xml:" << endl << pDoc.toString() << endl;
} catch (BeansException &ex) {
cout << "BeansException: " << ex.getMessage() << endl;
}
return 0;
}
|
Compile and link: g++ -g -o test testProgramMain.cpp src/corporation.cpp -Isrc/ -I/opt/include -lxerces-c -lgmp -lgmpxx -pthread -lxmlbeansxx /usr/lib/libxmlbeansxx.a /usr/lib/liblog4cxx.a -lapr-1 -laprutil-1
(Static link)
File: CorporationMegaX.xml
-
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="corporationInfo.xsd">
<Corporation>
<Name>Corporation MegaX</Name>
<Phone>1-800-555-1212</Phone>
<Fax>1-877-555-1212</Fax>
<Address>512 Megacorp Way, Gotham City</Address>
</Corporation>
<People>
<!-- The Boss -->
<Employee TaxStatus="US-W2" Gender="Male" Desc="OnSite">
<Name>Mr Grand Kahuna</Name>
<US-W2>
<EmpNumber>1</EmpNumber>
<Manager>None</Manager>
<YearStart>1998</YearStart>
</US-W2>
<Data>
<WorkPhone>1-800-555-1213</WorkPhone>
<CellPhone>1-800-555-1214</CellPhone>
<Address>100 Cherry Hill Lane, Gotham City</Address>
</Data>
</Employee>
<!-- The Consultant -->
<Employee TaxStatus="US-1099" Gender="Male" Desc="OnSite">
<Name>Mr Special Tee</Name>
<US-1099>
<SsnNumber>123-45-6788</SsnNumber>
<CorpName>ABC Consulting</CorpName>
<Relationship>CorpToIndividual</Relationship>
</US-1099>
<Data>
<WorkPhone>1-800-555-1215</WorkPhone>
<CellPhone>1-800-555-1216</CellPhone>
<Address>200 Lookout Hill, Gotham City</Address>
</Data>
</Employee>
<!-- The Secratary -->
<Employee TaxStatus="US-W2" Gender="Female" Desc="OnSite">
<Name>Mrs Jenny Reliable</Name>
<US-W2>
<EmpNumber>2</EmpNumber>
<Manager>Mr Grand Kahuna</Manager>
<YearStart>1999</YearStart>
</US-W2>
<Data>
<WorkPhone>1-800-555-1217</WorkPhone>
<CellPhone>1-800-555-1218</CellPhone>
<Address>300 Riverside View, Gotham City</Address>
</Data>
</Employee>
</People>
</root>
|
Test by running the resulting program: ./test
-
Locale: en_US.UTF-8
Corporation Name: Corporation MegaX
Corporation Address: 512 Megacorp Way, Gotham City
Employee name: Mr Grand Kahuna
Employee number: 1
Work phone: 1-800-555-1213
Employee name: Mr Special Tee
Employee SSN number: 123-45-6788
Work phone: 1-800-555-1215
Employee name: Mrs Jenny Reliable
Employee number: 2
Work phone: 1-800-555-1217
File (minimum) for Log4cxx: Log4cxxConfig.xml
-
<?xml version="1.0" encoding="UTF-8" ?>
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Output the log message to system console.
-->
<appender name="testConsoleAppender" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
</layout>
</appender>
<root>
<priority value="error" />
<appender-ref ref="testConsoleAppender"/>
</root>
<!-- Specify the level for some specific categories
-->
<category name="TestProgramMain" >
<priority value ="all" />
<!-- appender-ref ref="testConsoleAppender"/ -->
</category>
</log4j:configuration>
|
For more on Apache Log4cxx, see the YoLinux.com Log4cxx tutorial
Books: |
-
|
|