Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - RelaxNG object model generator / parser

Say I have this XML:

<domain type='qemu' xmlns:qemu='http://libirt.org/schemas/domain/qemu/1.0'>
  <name>QEmu-fedora-i686</name>
  <memory>219200</memory>
  <os>
    <type arch='i686' machine='pc'>hvm</type>
  </os>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
  </devices>
  <qemu:commandline>
    <qemu:arg value='-newarg'/>
    <qemu:env name='QEMU_ENV' value='VAL'/>
  </qemu:commandline>
</domain>

this XML is validated via a RelaxNG schema, which is located here:
http://libvirt.org/git/?p=libvirt.git;a=tree;f=docs/schemas;hb=HEAD

Now I want to generate classes (persistent source files) out of this schema, to make me able to work with this model in an object oriented way
So that I

  • don't have to bother working with XML parsers
  • can work with these objects, but they are always conform with the RelaxNG schema
  • get IDE auto completion
  • get validation through the Python interpreter

In the end I want to be able to do something like this:

d = Domain()
d.name = 'QEmu-fedora-i686'
d.memory = 219200
d.os = Os('hvm')
d.os.type.arch = 'i686'
d.os.machine = 'pc'
...

I'm thinking about writing something like that (a generic RelaxNG object model generator) on my own, but I want to know if anyone can help me how to start and if there are some python libraries that help me doing that (lxml?)


Approach 1: Convert RelaxNG to XSD, then generate object model with generateDS

As tito suggested in his answer, I downloaded the latest trang from here. Then I executed trang like this: java -jar trang.jar domain.rng domain.xsd. This already gave me some warnings:

/tmp/libvirt/schemas/domaincommon.rng:531:17: warning: cannot represent an optional group of attributes; approximating 
/tmp/libvirt/schemas/domaincommon.rng:687:15: warning: choice between attributes and children cannot be represented; approximating
/tmp/libvirt/schemas/domaincommon.rng:955:15: warning: choice between attributes and children cannot be represented; approximating
/tmp/libvirt/schemas/domaincommon.rng:1041:15: warning: choice between attributes and children cannot be represented; approximating
/tmp/libvirt/schemas/domaincommon.rng:1260:15: warning: choice between attributes and children cannot be represented; approximating
/tmp/libvirt/schemas/domaincommon.rng:1817:17: warning: choice between attributes and children cannot be represented; approximating
/tmp/libvirt/schemas/domaincommon.rng:1808:15: warning: choice between attributes and children cannot be represented; approximating
/tmp/libvirt/schemas/domaincommon.rng:1924:15: warning: choice between attributes and children cannot be represented; approximating
/tmp/libvirt/schemas/domaincommon.rng:2240:15: warning: choice between attributes and children cannot be represented; approximating

Unfortunately, trying to generate an object model out of the generated XSD failed:

$ generateDS.py domain.xsd
Traceback (most recent call last):
  File "/usr/local/bin/generateDS.py", line 5, in <module>
    pkg_resources.run_script('generateDS==2.7b', 'generateDS.py')
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 467, in run_script
    self.require(requires)[0].run_script(script_name, ns)
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 1200, in run_script
    execfile(script_filename, namespace, namespace)
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/generateDS.py", line 4709, in <module>
    main()
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/generateDS.py", line 4703, in main
    processIncludes, superModule=superModule)
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/generateDS.py", line 4433, in parseAndGenerate
    inpath=xschemaFileName)
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/process_includes.py", line 49, in process_include_files
    prep_schema_doc(infile, outfile, inpath, options)
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/process_includes.py", line 197, in prep_schema_doc
    collect_inserts(root1, params, inserts, options)
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/process_includes.py", line 158, in collect_inserts
    collect_inserts_aux(child, params, inserts, options)
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/process_includes.py", line 175, in collect_inserts_aux
    collect_inserts(root, params, inserts, options)
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/process_includes.py", line 158, in collect_inserts
    collect_inserts_aux(child, params, inserts, options)
  File "/usr/local/lib/python2.7/dist-packages/generateDS-2.7b-py2.7.egg/EGG-INFO/scripts/process_includes.py", line 165, in collect_inserts_aux
    root = etree.fromstring(string_content, base_url=params.base_url)
  File "lxml.etree.pyx", line 2743, in lxml.etree.fromstring (src/lxml/lxml.etree.c:52665)
  File "parser.pxi", line 1573, in lxml.etree._parseMemoryDocument (src/lxml/lxml.etree.c:79932)
  File "parser.pxi", line 1452, in lxml.etree._parseDoc (src/lxml/lxml.etree.c:78774)
  File "parser.pxi", line 960, in lxml.etree._BaseParser._parseDoc (src/lxml/lxml.etree.c:75389)
  File "parser.pxi", line 564, in lxml.etree._ParserContext._handleParseResultDoc (src/lxml/lxml.etree.c:71739)
  File "parser.pxi", line 645, in lxml.etree._handleParseResult (src/lxml/lxml.etree.c:72614)
  File "parser.pxi", line 585, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:71955)
lxml.etree.XMLSyntaxError: attributes construct error, line 106, column 50

These are the XSDs that where generated by trang (and produced that error):

http://mackaz.de/so/basictypes.xsd
http://mackaz.de/so/domain.xsd
http://mackaz.de/so/domaincommon.xsd http://mackaz.de/so/networkcommon.xsd
http://mackaz.de/so/qemu.xsd
http://mackaz.de/so/storageencryption.xsd

With some debugging I found out the source of the generateDS error. In file basictypes.xsd, there seem to be some wrong expressions (there are three double quotes in each element):

<xs:simpleType name="filePath">
  <xs:restriction base="xs:string">
    <xs:pattern value="[a-zA-Z0-9_\.\+\-\\&amp;"'&lt;&gt;/%]+"/>
  </xs:restriction>
</xs:simpleType>
<xs:simpleType name="absFilePath">
  <xs:restriction base="xs:string">
    <xs:pattern value="/[a-zA-Z0-9_\.\+\-\\&amp;"'&lt;&gt;/%]+"/>
  </xs:restriction>
</xs:simpleType>
<xs:simpleType name="absDirPath">
  <xs:restriction base="xs:string">
    <xs:pattern value="/[a-zA-Z0-9_\.\+\-\\&amp;"'&lt;&gt;/%]*"/>
  </xs:restriction>
</xs:simpleType>

I replaced these expressions with different values (which are now not reflecting the schema, but make generateDS happy):

<xs:simpleType name="filePath">
    <xs:restriction base="xs:string">
        <xs:pattern value="[a-zA-Z0-9\.\-]+"/>
    </xs:restriction>
</xs:simpleType>
<xs:simpleType name="absFilePath">
    <xs:restriction base="xs:string">
        <xs:pattern value="[a-zA-Z0-9\.\-]+"/>
    </xs:restriction>
</xs:simpleType>
<xs:simpleType name="absDirPath">
    <xs:restriction base="xs:string">
        <xs:pattern value="[a-zA-Z0-9\.\-]+"/>
    </xs:restriction>
</xs:simpleType>

Et voila - it works, generateDS is not complaining anymore and produces this outputfile:

http://mackaz.de/so/domain.py

Now I have to investigate that file and see if it can help me (as expected, it's pretty big: 28157 LOC...).

like image 267
Wolkenarchitekt Avatar asked May 22 '26 13:05

Wolkenarchitekt


1 Answers

If you're able to convert rng to xsd (check out the conversions links on relaxng website), you could use generateDS project.

  1. Use generateDS to convert xsd files into an importable python file containing all the classes.
  2. In the generate python file, you can use parse(), and it will give you a root python object with the same behavior that you're asking for.
  3. Later, you can even export to xml your root object using the export() function
like image 113
tito Avatar answered May 24 '26 03:05

tito



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!