4

In spite of being a total newbie in the xml parsing arena, I was able to xsd to create valid c++ and compile and link successfully, but the compiler optimized(?) away the instantiation. So, starting at step one, I try the hello world xml example at CodeSynthesis. But that fails:

[wally@lenovotower xml]$ make hello
xsdcxx cxx-tree hello.xsd
g++ -c -o helloschema.o hello.cxx
g++ -g -o hello -lxerces-c helloschema.o hello.c++
[wally@lenovotower xml]$ ./hello
hello.xml:2:8 error: no declaration found for element 'hello'
hello.xml:4:13 error: no declaration found for element 'greeting'
hello.xml:6:9 error: no declaration found for element 'name'
hello.xml:7:9 error: no declaration found for element 'name'
hello.xml:8:9 error: no declaration found for element 'name'

hello.c++:

#include <iostream>
#include <stdio.h>
#include "hello.hxx"
using namespace std;
int main (void)
{
        try {
                auto_ptr<hello_t> h (hello ("hello.xml"));

                for (hello_t::name_const_iterator i (h->name ().begin()); 
                        i != h->name().end();
                        ++i)
                        cout << h->greeting () << ", " << *i << "!" << endl;    
        }
        catch (const xml_schema::exception& e)
        {
                cerr << e << endl;
                return 1;
        }
        return 0;
}

hello.xml:

<?xml version="1.0"?>
<hello>

  <greeting>Hello</greeting>

  <name>sun</name>
  <name>moon</name>
  <name>world</name>

</hello>

hello.xsd:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

 <xs:complexType name="hello_t">
  <xs:sequence> 
   <xs:element name="greeting" type="xs:string"/>
   <xs:element name="name" type="xs:string" maxOccurs="unbounded"/>
  </xs:sequence>
 </xs:complexType>

 <xs:element name="hello" type="hello_t"/> 

</xs:schema> 

I think this is exactly what it says to do, but the commands don't work exactly as documented. I discovered xsdcxx seems to do the right thing (unlike xsd which generates C# or vb.net output).

[wally@lenovotower xml]$ xsdcxx --version
CodeSynthesis XSD XML Schema to C++ compiler 3.3.0
Copyright (C) 2005-2010 Code Synthesis Tools CC

Also, I don't include an -I(dir) and it compiles happily. Could it be using the wrong include file somehow?

What am I doing wrong? Maybe xsd isn't the right tool?

Erik Sjölund
  • 10,690
  • 7
  • 46
  • 74
wallyk
  • 56,922
  • 16
  • 83
  • 148

3 Answers3

3

There are some options. The schema location can be provided in the file hello.xml:

<?xml version="1.0"?>
<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation="hello.xsd">

  <greeting>Hello</greeting>

  <name>sun</name>
  <name>moon</name>
  <name>world</name>

</hello>

Another option is to provide the schema location in the file hello.c++

If we assume the schema file is located at the filepath /some/file/path/hello.xsd

we should instead of writing

auto_ptr<hello_t> h (hello ("hello.xml"));

write

xml_schema::properties properties;
properties.no_namespace_schema_location("file:///some/file/path/hello.xsd");
auto_ptr<hello_t> h (hello ("hello.xml", 0, properties));

You can read more about this in the Codesynthesis FAQ:

Why do I get "error: no declaration found for element 'root-element'" when I try to parse a valid XML document?

Erik Sjölund
  • 10,690
  • 7
  • 46
  • 74
2

Personally I find the combination of Python and lxml to be pretty invaluable. Your XML document and the corresponding XML schema work just fine:

from lxml import etree

xsddoc = etree.parse('hello.xsd')
xsd = etree.XMLSchema(xsddoc)
xml_parser = etree.XMLParser(schema=xsd)
xmldoc = etree.parse('hello.xml', parser=xml_parser)

I didn't get any errors from that. I will say, however, that even though lxml doesn't require you to use xsi:noNamespaceSchemaLocation since it loads the schema you specify, you should still use it as long as you're not using namespaces. Just because one XML parser is flexible, others might not be, a fact that it seems you might have figured out the hard way. If you do use namespaces, use xsi:schemaLocation instead of xsi:noNamespaceSchemaLocation. Also note that you MUST declare the xsi namespace via the xmlns:xsi attribute to be able to use the xsi:* attributes.

An example using xsi:noNamespaceSchemaLocation:

<hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="hello.xsd">
  ...
</hello>
  • How? What is it you're confused about? –  Jun 18 '11 at 05:35
  • I am bothered by this, even if it did work (which I have not tried). The XML my program is going to parse arrives via network from potentially multiple sources: how could those sources possibly know the schema *path*? – wallyk Jun 19 '11 at 14:19
  • 1
    Ah, that's the problem... After a quick Google search and a bit of link following, [documentation for validation](http://www.codesynthesis.com/projects/xsd/documentation/cxx/tree/guide/#5.1) turned up. –  Jun 19 '11 at 17:57
  • I suspect that is a promising lead. I spent a half hour trying to incorporate the first of that into the test, but I got stubborn compilation problems: *error: no matching function for call to ‘std::auto_ptr::auto_ptr(std::auto_ptr, int, xml_schema::properties&)’*. The hint about precompiling the schema is the right thing to do; alas it is late, so I'll look into it more tomorrow. Thanks for the followup! – wallyk Jun 20 '11 at 06:18
  • This answer led to the proper conclusion which was that `xsd` is far too heavyweight a parser for our use. I've switched happily and extremely productively to rapidxml instead. http://rapidxml.sourceforge.net/index.htm – wallyk Jul 11 '11 at 04:47
1

EDIT: Ignore this answer. I'm leaving it up because the comments are worth saving. Your XSD says:

 <xs:complexType name="hello_t">

but your XML says:

<hello>
...
</hello>

Perhaps the XSD should be:

 <xs:complexType name="hello">

Also, the XML is missing an xsi:schemaLocation declaration. It might help to have one.

Dan Breslau
  • 11,472
  • 2
  • 35
  • 44
  • 1
    Or xsi:noNamespaceSchemaLocation since namespaces aren't being used at all. –  Jun 18 '11 at 05:09
  • I had what the example has, but changing `hello_t` to `hello` in two places in the .xsd causes compilation `error: ‘hello_t’ was not declared in this scope`; changing that also gives a different compile error `error: no matching function for call to ‘std::auto_ptr::auto_ptr(hello)’` – wallyk Jun 18 '11 at 05:23
  • @Chrono: what does that do, and where does that go? – wallyk Jun 18 '11 at 05:23
  • 1
    `` is what your `` element should look like. Whether that will help with xsdcxx is still a mystery until you try it. :) –  Jun 18 '11 at 05:32
  • @wallyk: My mistake; I shouldn't have been trying to give XSD advice so late at night (or early in the morning :-) The original XSD is correct as it was. To understand the problem, I think I'd need to look at the generated C++ code, which might or might not be a worthwhile exercise. – Dan Breslau Jun 18 '11 at 15:22