--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Orb/python/orb/XSDToPackageDef.py Wed Aug 11 14:49:30 2010 +0100
@@ -0,0 +1,925 @@
+# Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved.
+# This component and the accompanying materials are made available under the terms of the License
+# "Eclipse Public License v1.0" which accompanies this distribution,
+# and is available at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# Checks links in DITA XML and reports issues.
+
+"""
+Created on 24 May 2010
+
+@author: p2ross
+"""
+import os
+import sys
+import logging
+#import pprint
+#import fnmatch
+#import re
+import string
+import time
+from optparse import OptionParser#, check_choice
+try:
+ from xml.etree import cElementTree as etree
+except ImportError:
+ from xml.etree import ElementTree as etree
+#import multiprocessing
+
+__version__ = "0.1.0"
+
+
+class XsdBase(object):
+ PREFIX = '{http://www.w3.org/2001/XMLSchema}'
+ def _addSchemaPrefix(self, theTag):
+ return '%s%s' % (self.PREFIX, theTag)
+
+ def _tagSchemaMatches(self, theN, theTag):
+ return theN.tag == self._addSchemaPrefix(theTag)
+
+ def _tagSchemaMatchesList(self, theN, theTagS):
+ for aTag in theTagS:
+ if theN.tag == self._addSchemaPrefix(aTag):
+ return True
+ return False
+
+ def _stripSchemaPrefix(self, theN):
+ """Returns theNode.tag without the schema prefix."""
+ return theN.tag[len(self.PREFIX):]
+
+class XsdNodeBase(XsdBase):
+ PREFIX = '{http://www.w3.org/2001/XMLSchema}'
+ def __init__(self, theN):
+ super(XsdNodeBase, self).__init__()
+ self._name = theN.get('name')
+ self._ref = theN.get('ref')
+ # This will be prefix+element
+ self._tag = theN.tag
+ self._min = int(theN.get('minOccurs') or 1)
+ if theN.get('maxOccurs') == 'unbounded':
+ self._max = -1
+ else:
+ self._max = int(theN.get('maxOccurs') or 1)
+ logging.debug(
+ 'XsdNodeBase.__init__(): tag=%s, name=%s, ref=%s, min=%d, max=%d',
+ self.tag,
+ self._name,
+ self._ref,
+ self._min,
+ self._max,
+ )
+
+ @property
+ def tag(self):
+ return self._tag[len(self.PREFIX):]
+
+ @property
+ def attrRef(self):
+ return self._ref
+
+ @property
+ def attrName(self):
+ return self._name
+
+ @property
+ def isUnbounded(self):
+ return self._max == -1
+
+ @property
+ def minOccurs(self):
+ return self._min
+
+ @property
+ def maxOccurs(self):
+ return self._max
+
+ @property
+ def boundedString(self):
+ """Returns a natural language description of bounds."""
+ if self._min == 1 and self._max == 1:
+ return ''
+ elif self._min == 0:
+ if self._max == 1:
+ # minOccurs="0" -> 'optional'
+ return 'optional'
+ elif self.isUnbounded:
+ # minOccurs="0" maxOccurs="unbounded" -> 'any number'
+ return 'any number'
+ else:
+ # minOccurs="0" maxOccurs="42" -> 'up to 42'
+ return 'up to %d' % self._max
+ elif self.isUnbounded:
+ # minOccurs="17" maxOccurs="unbounded" -> 'at least 17'
+ return 'at least %d' % self._min
+ # minOccurs="17" maxOccurs="42" -> 'at least 17 and up to 42'
+ return 'at least %d, and up to %d' % (self._min, self._max)
+
+class Attribute(XsdNodeBase):
+ """Represents an element describing an attribute."""
+ def __init__(self, theN):
+ super(Attribute, self).__init__(theN)
+ assert(self._tagSchemaMatches(theN, 'attribute'))
+ self._default = theN.get('default')
+ self._use = theN.get('use')
+
+ @property
+ def default(self):
+ return self._default
+
+ @property
+ def use(self):
+ return self._use
+
+class RefBase(XsdNodeBase):
+ """Represents a reference to a group or element"""
+ def __init__(self, theN):
+ super(RefBase, self).__init__(theN)
+ assert(self._tagSchemaMatchesList(theN, ('group', 'element')))
+ assert(self.attrRef is not None)
+
+ @property
+ def isSequence(self):
+ return False
+
+class RefSequence(XsdNodeBase):
+ """Holds information on an xs:all, xs:choice or xs:sequence."""
+ def __init__(self, theN):
+ super(RefSequence, self).__init__(theN)
+ assert(self._tagSchemaMatchesList(theN, ('all', 'choice', 'sequence'))), 'Tag %s not in list' % theN.tag
+ # List of class RefBase or, recursively, a class RefSequence
+ self._refS = []
+ self._type = self.tag
+ for aChild in theN.getchildren():
+ if not self._tagSchemaMatchesList(aChild, ('group', 'all', 'choice', 'sequence')):
+ continue
+ #self._type = self._stripSchemaPrefix(aChild)
+ if self._tagSchemaMatches(aChild, 'group'):
+ self._refS.append(RefBase(aChild))
+ elif self._tagSchemaMatchesList(
+ aChild,
+ ('choice', 'sequence', 'any',)
+ ):
+ self._refS.append(RefSequence(aChild))
+
+ def genRefs(self):
+ """Generates the list of RefBase or RefSequence"""
+ for aRef in self._refS:
+ yield aRef
+
+ @property
+ def numRefs(self):
+ return len(self._refS)
+
+ @property
+ def refs(self):
+ return self._refS
+
+ @property
+ def isSequence(self):
+ return True
+
+ def qualifierString(self):
+ if self._type == 'all':
+ return '(any number, any order)'
+ elif self._type == 'choice':
+ return '(any number)'
+ elif self._type == 'sequence':
+ return ''
+ return 'Unknown'
+
+ def joinString(self):
+ if self._type == 'all':
+ return ' or '
+ elif self._type == 'choice':
+ return ' or '
+ elif self._type == 'sequence':
+ return ' then '
+ return ''
+
+ @property
+ def seqType(self):
+ return self._type
+
+class DefBase(XsdNodeBase):
+ """Represents a definition of a group, element or complexType"""
+ def __init__(self, theN):
+ super(DefBase, self).__init__(theN)
+ assert(self._tagSchemaMatchesList(theN, ('group', 'element', 'complexType'))), 'Tag %s not in list' % theN.tag
+ assert(self.attrName is not None or self._tagSchemaMatches(theN, 'complexType'))
+ # List of class RefBase of class RefSequence
+ self._refS = []
+
+ def genRefs(self):
+ """Generates the list of RefBase"""
+ for aRef in self._refS:
+ yield aRef
+
+ @property
+ def numRefs(self):
+ return len(self._refS)
+
+ @property
+ def refs(self):
+ return self._refS
+
+class GroupDef(DefBase):
+ """Represents the definition of a group i.e. <xs:group name="...">...</xs:group>.
+ See: http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-group"""
+ def __init__(self, theN):
+ super(GroupDef, self).__init__(theN)
+ assert(theN.tag == self._addSchemaPrefix('group'))
+ # http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-group
+ # Content: (annotation?, (all | choice | sequence)?)
+ self._type = None
+ for aChild in theN.getchildren():
+ if self._tagSchemaMatchesList(aChild, ('all', 'choice', 'sequence')):
+ self._type = self._stripSchemaPrefix(aChild)
+ else:
+ # Unrecognised element or annotation
+ continue
+ if self._type is not None:
+ # Read grand children and break
+ for aGrandChild in aChild.getchildren():
+ if aGrandChild.get('ref') is not None \
+ and self._tagSchemaMatchesList(
+ aGrandChild,
+ (
+ 'element',
+ 'group',
+ #'choice',
+ #'sequence',
+ #'any',
+ )):
+ self._refS.append(RefBase(aGrandChild))
+ break
+
+ def __str__(self):
+ #print 'TRACE:', self._refS
+ return self.joinString().join(['%s' % r.attrRef for r in self._refS]) \
+ + ' ' \
+ + self.qualifierString()
+
+ def qualifierString(self):
+ if self._type == 'all':
+ return '(any number, any order)'
+ elif self._type == 'choice':
+ return '(any number)'
+ elif self._type == 'sequence':
+ return ''
+ return 'Unknown'
+
+ def joinString(self):
+ if self._type == 'all':
+ return ' or '
+ elif self._type == 'choice':
+ return ' or '
+ elif self._type == 'sequence':
+ return ' then '
+ return ''
+
+ @property
+ def groupType(self):
+ return self._type
+
+class ComplexTypeDef(DefBase):#XsdNodeBase):
+ """Represents the definition of a complexType definition i.e. <xs:complexType name="...">...</xs:group>.
+ See: http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-complexType"""
+ def __init__(self, theN):
+ super(ComplexTypeDef, self).__init__(theN)
+ assert(theN.tag == self._addSchemaPrefix('complexType'))
+ # http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-complexType
+ # Simplified content: ((group | all | choice | sequence)?
+ self._type = None
+ # Get xs:attribute
+ self._attrS = []
+ for aChild in theN.getchildren():
+ # We only handle complexType
+ if not self._tagSchemaMatchesList(
+ aChild,
+ ('group', 'all', 'choice', 'sequence', 'attribute')):
+ # Unrecognised element or annotation
+ continue
+ self._type = self._stripSchemaPrefix(aChild)
+ if self._tagSchemaMatches(aChild, 'group'):
+ self._refS.append(RefBase(aChild))
+ elif self._tagSchemaMatchesList(
+ aChild,
+ ('choice', 'sequence', 'any',),
+ ):
+ self._refS.append(RefSequence(aChild))
+ elif self._tagSchemaMatches(aChild, 'attribute'):
+ self._attrS.append(Attribute(aChild))
+
+ @property
+ def groupType(self):
+ return self._type
+
+ def namedAttribute(self, theName):
+ """Returns an Attribute object or None."""
+ for anA in self._attrS:
+ if anA.attrName == theName:
+ return anA
+
+class ElementDef(DefBase):
+ """Represents the definition of a element definition i.e. <xs:element name="...">...</xs:group>.
+ See: http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-group"""
+ def __init__(self, theN):
+ super(ElementDef, self).__init__(theN)
+ assert(theN.tag == self._addSchemaPrefix('element'))
+ # http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-element
+ # Simplified content: (annotation?, ((simpleType | complexType)?
+ self._type = None
+ self._complexType = None
+ for aChild in theN.getchildren():
+ # We only handle complexType
+ if not self._tagSchemaMatchesList(aChild, ('complexType',)):
+ # Unrecognised element or annotation
+ continue
+ # Process a <complexType>
+ self._complexType = ComplexTypeDef(aChild)
+ break
+
+ @property
+ def complexType(self):
+ return self._complexType
+
+class GroupRef(RefBase):
+ """Represents a reference of a group i.e. <xs:group ref="..." .../>.
+ See: http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-group"""
+ def __init__(self, theN):
+ super(GroupRef, self).__init__(theN)
+ assert(theN.tag == self._addSchemaPrefix('group'))
+
+class ElementRef(RefBase):
+ """Represents a reference to an element i.e. <xs:element ref="..." .../>.
+ See: http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-group"""
+ def __init__(self, theN):
+ super(ElementRef, self).__init__(theN)
+ assert(theN.tag == self._addSchemaPrefix('element'))
+
+class XsdToPackageDef(XsdBase):
+ """Create a PackageDef.xml file from a set of XSD files."""
+ DUMP_PREFIX = ' '
+ def __init__(self, thePrefix):#, theOutFile=None, theTitle=''):
+ super(XsdToPackageDef, self).__init__()
+ # Maps of group definitions and references
+ self._groupDefMap = {}
+ self._groupRefMap = {}
+ # Maps of element definitions and references
+ self._elemDefMap = {}
+ self._elemRefMap = {}
+ # Top level complex types
+ self._complexTypeMap = {}
+ # Element prefix
+ self._prefix = thePrefix
+
+ ##########################
+ # Section: Add an XSD file
+ ##########################
+ def addXsdFile(self, thePath):
+ """Read an XSD and add it to the representation."""
+ t = etree.parse(thePath)
+ r = t.getroot()
+ self._addGroups(r)
+ self._addElements(r)
+ self._addComplexTypes(r)
+
+ def addXsdPath(self, thePath):
+ if os.path.isfile(thePath):
+ if os.path.splitext(thePath)[1].lower() == '.xsd':
+ self.addXsdFile(thePath)
+ elif os.path.isdir(thePath):
+ for aName in os.listdir(thePath):
+ self.addXsdPath(os.path.join(thePath, aName))
+
+ def _addGroups(self, root):
+ """Adds to the group maps."""
+ for anE in root.getchildren():
+ if self._tagSchemaMatches(anE, 'group'):
+ if anE.get('name') is not None:
+ self._groupDefMap[anE.get('name')] = GroupDef(anE)
+ elif anE.get('ref') is not None:
+ self._groupRefMap[anE.get('ref')] = GroupRef(anE)
+
+ def _addElements(self, root):
+ """Adds to the element maps."""
+ for anE in root.getchildren():
+ if self._tagSchemaMatches(anE, 'element'):
+ if anE.get('name') is not None:
+ self._elemDefMap[anE.get('name')] = ElementDef(anE)
+ elif anE.get('ref') is not None:
+ self._elemRefMap[anE.get('ref')] = ElementRef(anE)
+
+ def _addComplexTypes(self, root):
+ for anE in root.getchildren():
+ if self._tagSchemaMatches(anE, 'complexType'):
+ self._complexTypeMap[anE.get('name')] = ComplexTypeDef(anE)
+ ##########################
+ # End: Add an XSD file
+ ##########################
+
+ ##########################
+ # Section: Query the IR
+ ##########################
+ def elemContains(self, theElemName):
+ """Returns a list of immediate child elements that this element contains."""
+ logging.debug('elemContains(%s)' % theElemName)
+ retVal = []
+ if not self._elemDefMap.has_key(theElemName):
+ return retVal
+ myElem = self._elemDefMap[theElemName]
+ if myElem.complexType is not None:
+ logging.debug('elemContains(): complexType: %s', myElem.complexType)
+ #print 'myElem', myElem
+ for aRef in myElem.complexType.genRefs():
+ logging.debug('elemContains(): complexType tag: %s, attrRef: %s',
+ aRef.tag,
+ aRef.attrRef,
+ )
+ self._addFromComplexTypeSequence(aRef, retVal)
+# myRef = aRef.attrRef
+# #print 'myRef', myRef
+# #if self._elemDefMap.has_key(myRef):
+# # retVal.append(myRef)
+# if self._groupDefMap.has_key(myRef):
+# self._addContainsGroup(myRef, retVal)
+# else:
+# retVal.append(myRef)
+ logging.debug('elemContains(%s) returns %s', theElemName, str(retVal))
+ return retVal
+
+ def _addFromComplexTypeSequence(self, theRefObj, theList):
+ """Recursively add containing elements."""
+ myRef = theRefObj.attrRef
+ logging.debug('_addFromComplexTypeSequence(%s):', myRef)
+ if theRefObj.isSequence:
+ for aSubRef in theRefObj.refs:
+ logging.debug('_addFromComplexTypeSequence(): recursing on: %s',
+ myRef)
+ self._addFromComplexTypeSequence(aSubRef, theList)
+ elif myRef is not None:
+ if self._groupDefMap.has_key(myRef):
+ self._addContainsGroup(myRef, theList)
+ else:
+ logging.debug('_addFromComplexTypeSequence(): adding: %s',
+ myRef)
+ theList.append(myRef)
+
+ def _addContainsGroup(self, theRef, theList):
+ logging.debug('_addContainsGroup(%s)' % theRef)
+ assert(self._groupDefMap.has_key(theRef))
+ for aRef in self._groupDefMap[theRef].genRefs():
+ #print 'TRACE: aRef', aRef.tag
+ logging.debug('_addContainsGroup(): aRef.tag: %s aRef.attrRef: %s' \
+ % (aRef.tag, aRef.attrRef))
+ if aRef.tag == 'element':
+ theList.append(aRef.attrRef)
+ elif aRef.tag == 'group' and self._groupDefMap.has_key(aRef.attrRef):
+ self._addContainsGroup(aRef.attrRef, theList)
+
+ ##########################
+ # End: Query the IR
+ ##########################
+
+ ##########################
+ # Section: Debug/trace
+ ##########################
+ def dump(self, s=sys.stdout):
+ s.write(' Group definitions '.center(75, '-')+'\n')
+ keyS = self._groupDefMap.keys()
+ keyS.sort()
+ for k in keyS:
+ s.write('%40s : %s\n' % (k, self._groupDefMap[k]))
+ s.write(' EOL '.center(75, '-')+'\n\n')
+ s.write(' Group references '.center(75, '-')+'\n')
+ keyS = self._groupRefMap.keys()
+ keyS.sort()
+ for k in keyS:
+ s.write('%40s : %s\n' % (k, self._groupRefMap[k]))
+ s.write(' EOL '.center(75, '-')+'\n\n')
+ s.write(' Element definitions '.center(75, '-')+'\n')
+ keyS = self._elemDefMap.keys()
+ keyS.sort()
+ for k in keyS:
+ s.write('%40s : %s\n' % (k, self._elemDefMap[k]))
+ s.write(' EOL '.center(75, '-')+'\n\n')
+ s.write(' Element references '.center(75, '-')+'\n')
+ keyS = self._elemRefMap.keys()
+ keyS.sort()
+ for k in keyS:
+ s.write('%40s : %s\n' % (k, self._elemRefMap[k]))
+ s.write(' EOL '.center(75, '-')+'\n\n')
+ s.write(' Complex types '.center(75, '-')+'\n')
+ keyS = self._complexTypeMap.keys()
+ keyS.sort()
+ for k in keyS:
+ s.write('%40s : %s\n' % (k, self._complexTypeMap[k]))
+ s.write(' EOL '.center(75, '-')+'\n\n')
+ s.write(' Parent to child relationship '.center(75, '-')+'\n')
+ # A map {element_name : [parent element, ...], ...}
+ myPcMap = self._retContainedByMap()
+ keyS = myPcMap.keys()
+ keyS.sort()
+ for k in keyS:
+ s.write('Child: %s\n' % k)
+ s.write(' Contained by: %s\n' % myPcMap[k])
+ s.write(' EOL '.center(75, '-')+'\n\n')
+ # Run through the elements
+ keyS = self._elemDefMap.keys()
+ keyS.sort()
+ for k in keyS:
+ myElem = self._elemDefMap[k]
+ s.write('Element: %s\n' % k)
+ if myElem.complexType is not None:
+ for aRef in myElem.complexType.genRefs():
+ #print 'TRACE: aRef', aRef
+ if aRef.isSequence:
+ self._dumpSequenceRef(s, aRef, level=1)
+ else:
+ self._dumpRef(s, aRef, level=1)
+ else:
+ s.write(' No complexType\n')
+ s.write('\n')
+
+ def _dumpRef(self, s, theRef, level=1):
+ assert(not theRef.isSequence)
+ if self._groupDefMap.has_key(theRef.attrRef):
+ s.write('%s%s %s [%s]\n' \
+ % (self.DUMP_PREFIX*level,
+ theRef.attrRef,
+ '(group)',
+ theRef.boundedString,
+ #self._groupDefMap[aRef.attrRef].boundedString,
+ )
+ )
+ self._dumpGroupRef(s, theRef.attrRef, level)
+ #for aGm in self._groupDefMap[aRef.attrRef].genRefs():
+ # print ' <%s> %s %s %s' \
+ # % (aGm.tag, aGm.attrName, aGm.attrRef, aGm.boundedString)
+ elif self._elemDefMap.has_key(theRef.attrRef):
+ s.write('%s%s %s\n' % (self.DUMP_PREFIX*level, theRef.attrRef, '(element)'))
+ elif self._complexTypeMap.has_key(theRef.attrRef):
+ s.write('%s%s %s\n' % (self.DUMP_PREFIX*level, theRef.attrRef, '(complex)'))
+ else:
+ s.write('%s%s %s\n' % (self.DUMP_PREFIX*level, theRef.attrRef, '(not in my IR)'))
+
+ def _dumpGroupRef(self, s, theR, level=1):
+ """Dump out references to groups, recursively using self._groupDefMap."""
+ assert(self._groupDefMap.has_key(theR))
+ if self._groupDefMap[theR].numRefs == 1 \
+ and self._groupDefMap[theR].refs[0].tag == 'element':
+ s.write('%sELEMENT<%s> %s %s "%s" [%s]\n' \
+ % (
+ self.DUMP_PREFIX*level,
+ self._groupDefMap[theR].refs[0].tag,
+ self._groupDefMap[theR].refs[0].attrName,
+ self._groupDefMap[theR].refs[0].attrRef,
+ self._groupDefMap[theR].refs[0],
+ self._groupDefMap[theR].refs[0].boundedString,
+ )
+ )
+ else:
+ s.write('%sGROUP <%s>%s\n' \
+ % (self.DUMP_PREFIX*level, self._groupDefMap[theR].tag, self._groupDefMap[theR]))
+ for aGm in self._groupDefMap[theR].genRefs():
+ #print '%s<%s> %s %s "%s"' \
+ # % (self.DUMP_PREFIX*level, aGm.tag, aGm.attrName, aGm.attrRef, aGm)#aGm.boundedString)
+ if aGm.tag == 'group' \
+ and aGm.attrRef \
+ and self._groupDefMap.has_key(aGm.attrRef):
+ self._dumpGroupRef(s, aGm.attrRef, level+1)
+ elif aGm.tag == 'element':
+ s.write('%sCHLDELE<%s> %s %s "%s"\n' \
+ % (self.DUMP_PREFIX*level, aGm.tag, aGm.attrName, aGm.attrRef, aGm))#aGm.boundedString)
+
+ def _dumpSequenceRef(self, s, theR, level=1):
+ """Dump out sequences recursively."""
+ assert(theR.isSequence)
+ for i, aRef in enumerate(theR.genRefs()):
+ if i > 0:
+ s.write('%s[%s]\n' % (self.DUMP_PREFIX*level, theR.joinString()))
+ #print '%sTRACE: _dumpSequenceRef aRef: %s' % (self.DUMP_PREFIX*level, aRef)
+ if aRef.isSequence:
+ self._dumpSequenceRef(s, aRef, level=level+1)
+ else:
+ self._dumpRef(s, aRef, level=level+1)
+ s.write('%s[%s]\n' % (self.DUMP_PREFIX*level, theR.qualifierString()))
+ ##########################
+ # End: Debug/trace
+ ##########################
+
+ ##########################
+ # Section: Output
+ ##########################
+ def _writeHeader(self, theS, theTitle):
+ self._writeLine(theS, '<?xml version="1.0" encoding="UTF-8"?>')
+ self._writeLine(theS, """<!DOCTYPE reference PUBLIC "-//OASIS//DTD DITA Reference//EN" "../../dtd/reference.dtd">""")
+ self._writeLine(theS, """<reference id="%sapiref" xml:lang="en-us">""" % self._prefix)
+ self._writeLine(theS, '<title>%s</title>' % theTitle)
+
+ def _writeLine(self, theS, theL):
+ theS.write(theL)
+ theS.write('\n')
+
+ def _write(self, theS, theStr):
+ theS.write(theStr)
+
+ def close(self, theS):
+ self._writeLine(theS, '</reference>')
+ theS.close()
+
+ def _retContainedByMap(self):
+ """Returns a map {element_name : [parent element, ...], ...}."""
+ retMap = {}
+ keyS = self._elemDefMap.keys()
+ # Ensure that every element is represented
+ for myName in keyS:
+ retMap[myName] = []
+ for myName in keyS:
+ myContainS = self.elemContains(myName)
+ for aChild in myContainS:
+ try:
+ retMap[aChild].append(myName)
+ except KeyError:
+ retMap[aChild] = [myName]
+ return retMap
+
+ def _retDirName(self, theName):
+ assert(theName.startswith(self._prefix))
+ # Slice the name to get the directory
+ # e.g. 'cxxVariableDeclarationFile' becomes 'cxxVariable'
+ # Special case where all ...Ref.dita are in cxxAPIMap/
+ if theName.endswith('Ref') \
+ or theName == 'cxxAPIMap':
+ return 'cxxAPIMap'
+ i = len(self._prefix) + 1
+ while i < len(theName) and theName[i] in string.lowercase:
+ i += 1
+ retVal = theName[:i]
+ # This is a bit clunky for these special cases
+ if retVal in ('cxxEnumerator', 'cxxEnumerators'):
+ retVal = 'cxxEnumeration'
+ return retVal
+
+ def _writeElementNameToFile(self, theS, theName):
+ if self._elemDefMap.has_key(theName) \
+ and theName.startswith(self._prefix):
+ # Slice the name to get the directory
+ theDir = self._retDirName(theName)
+ self._writeLine(theS, '<xref href="%s/%s.dita">%s</xref> ' \
+ % (theDir, theName, theName)
+ )
+ else:
+ # Write out as a keyword
+ self._writeLine(theS, '<keyword>%s</keyword>, ' % theName)
+
+ def _writeContentModelToStream(self, theS, theName):
+ assert(self._elemDefMap.has_key(theName))
+ hasWritten = False
+ myElem = self._elemDefMap[theName]
+ if myElem.complexType is not None:
+ for aRef in myElem.complexType.genRefs():
+ #print 'TRACE: aRef', aRef
+ if aRef.isSequence:
+ if self._writeContentModelSequenceRef(theS, aRef):
+ hasWritten = True
+ else:
+ if self._writeContentModelRef(theS, aRef):
+ hasWritten = True
+ return hasWritten
+
+ def _writeContentModelSequenceRef(self, theS, theR):
+ assert(theR.isSequence)
+ hasWritten = False
+ if theR.numRefs > 0:
+ self._write(theS, '(')
+ for i, aRef in enumerate(theR.genRefs()):
+ if i > 0:
+ self._writeLine(theS, ' %s ' % theR.joinString())
+ hasWritten = True
+ if aRef.isSequence:
+ if self._writeContentModelSequenceRef(theS, aRef):
+ hasWritten = True
+ else:
+ if self._writeContentModelRef(theS, aRef):
+ hasWritten = True
+ if theR.qualifierString():
+ self._writeLine(theS, '<i>%s</i>' % theR.qualifierString())
+ if theR.numRefs > 0:
+ self._write(theS, ')')
+ return hasWritten
+
+ def _writeContentModelRef(self, theS, theR):
+ assert(not theR.isSequence)
+ hasWritten = False
+ if self._groupDefMap.has_key(theR.attrRef):
+ #s.write('%s %s\n' % (theR.attrRef, '(group)'))
+ self._writeContentModelGroupRefToStream(theS, theR)#.attrRef)
+ hasWritten = True
+ elif self._elemDefMap.has_key(theR.attrRef):
+ pass#s.write('%s %s\n' % (theR.attrRef, '(element)'))
+ elif self._complexTypeMap.has_key(theR.attrRef):
+ pass#s.write('%s %s\n' % (theR.attrRef, '(complex)'))
+ else:
+ #s.write('%s %s\n' % (theR.attrRef, '(not in my IR)'))
+ self._writeLine(theS, '<keyword>%s</keyword>, ' % theR.attrRef)
+ hasWritten = True
+ return hasWritten
+
+ def _writeContentModelGroupRefToStream(self, theS, theR):
+ assert(self._groupDefMap.has_key(theR.attrRef))
+ myGroup = self._groupDefMap[theR.attrRef]
+ if myGroup.numRefs == 1 \
+ and myGroup.refs[0].tag == 'element':
+# s.write('%sELEMENT<%s> %s %s "%s"\n' \
+# % (
+# self.DUMP_PREFIX*level,
+# self._groupDefMap[theR.attrRef].refs[0].tag,
+# self._groupDefMap[theR.attrRef].refs[0].attrName,
+# self._groupDefMap[theR.attrRef].refs[0].attrRef,
+# self._groupDefMap[theR.attrRef].refs[0],
+# )
+# )
+ #self._write(theS, '(')
+ aN = myGroup.refs[0].attrRef
+ self._writeElementNameToFile(theS, aN)
+ #self._writeLine(theS, '<xref href="%s/%s.dita">%s</xref>, %s' \
+ # % (aN, aN, aN, theR.boundedString))
+ if theR.boundedString:
+ self._writeLine(theS, '(<i>%s</i>)' % theR.boundedString)
+ #self._write(theS, ')')
+ else:
+ #s.write('%sGROUP <%s>%s\n' \
+ # % (self.DUMP_PREFIX*level, self._groupDefMap[theR.attrRef].tag, self._groupDefMap[theR.attrRef]))
+ if myGroup.numRefs > 0:
+ self._write(theS, '(')
+ for i, aGm in enumerate(myGroup.genRefs()):
+ #print '%s<%s> %s %s "%s"' \
+ # % (self.DUMP_PREFIX*level, aGm.tag, aGm.attrName, aGm.attrRef, aGm)#aGm.boundedString)
+ if i > 0:
+ self._writeLine(theS, myGroup.joinString())
+ if aGm.tag == 'group' \
+ and aGm.attrRef \
+ and self._groupDefMap.has_key(aGm.attrRef):
+ self._writeContentModelGroupRefToStream(theS, aGm)#.attrRef)
+ elif aGm.tag == 'element' \
+ and aGm.attrRef:
+ self._writeElementNameToFile(theS, aGm.attrRef)
+ #if self._elemDefMap.has_key(aGm.attrRef):
+ # aN = aGm.attrRef
+ # self._writeLine(theS, '<xref href="%s/%s.dita">%s</xref>, ' % (aN, aN, aN))
+ #else:
+ # self._writeLine(theS, '<keyword>%s</keyword>, ' % aGm.attrRef)
+ #elif aGm.tag == 'element':
+ # s.write('%sCHLDELE<%s> %s %s "%s"\n' \
+ # % (self.DUMP_PREFIX*level, aGm.tag, aGm.attrName, aGm.attrRef, aGm))#aGm.boundedString)
+ self._writeLine(theS, self._groupDefMap[theR.attrRef].qualifierString())
+ if myGroup.numRefs > 0:
+ self._write(theS, ')')
+
+ def writeToFile(self, thePath, theTitle):
+ myS = open(thePath, 'w')
+ self._writeHeader(myS, theTitle)
+ #self.dump()
+ myChildParentMap = self._retContainedByMap()
+ #print 'TRACE: myChildParentMap', myChildParentMap
+ # Run through the elements
+ keyS = self._elemDefMap.keys()
+ keyS.sort()
+ for myName in keyS:
+ myElem = self._elemDefMap[myName]
+ logging.info('Writing element: <%s>' % myName)
+ self._writeLine(myS, '<reference id="%s-reference" xml:lang="en-us">' % myName)
+ self._writeLine(myS, '<title>Element: %s</title>' % myName)
+ self._writeLine(myS, '<refbody>')
+ # Section: Contained by
+ self._writeLine(myS, '<section id="%s-containedBy-section" outputclass="elementContainedBy">' % myName)
+ self._writeLine(myS, '<title>Contained by</title>')
+ self._writeLine(myS, '<p id="%s-containedBy-p">' % myName)
+ for aParent in myChildParentMap[myName]:
+ self._writeElementNameToFile(myS, aParent)
+ #if self._elemDefMap.has_key(aParent):
+ # self._writeLine(myS, '<xref href="%s/%s.dita">%s</xref>, ' \
+ # % (aParent, aParent, aParent))
+ #else:
+ # # Write out as a keyword
+ # self._writeLine(myS, '<keyword>%s</keyword>, ' % aParent)
+ self._writeLine(myS, '</p>')
+ self._writeLine(myS, '</section>')
+ # Section: Contains
+ self._writeLine(myS,
+ '<section id="%s-contains-section" outputclass="elementContains">' % myName)
+ self._writeLine(myS, '<title>Contains</title>')
+ self._writeLine(myS, '<p id="%s-contains-p">' % myName)
+ myContainS = self.elemContains(myName)
+ myContainS.sort()
+ #print 'myContainS', myContainS
+ for aN in myContainS:
+ self._writeElementNameToFile(myS, aN)
+ self._writeLine(myS, '</p>')
+ self._writeLine(myS, '</section>')
+ # Section: Content Model
+ self._writeLine(myS, '<section id="%s-contentModel-section" outputclass="elementContentModel">' % myName)
+ self._writeLine(myS, '<title>Content Model</title>')
+ self._writeLine(myS, '<p id="%s-contentModel-p">' % myName)
+ # Content model contents
+ if not self._writeContentModelToStream(myS, myName):
+ self._writeLine(myS, 'No content.')
+ self._writeLine(myS, '</p>')
+ self._writeLine(myS, '</section>')
+ # Section: Attributes - empty
+ self._writeLine(myS, '<section id="%s-attList-section" outputclass="elementAttList" />' % myName)
+ # Section: classValue
+ self._writeLine(myS, '<section id="%s-classValue-section" outputclass="elementClassValue">' % myName)
+ self._writeLine(myS, '<title>Inheritance</title>')
+ self._writeLine(myS, '<p id="%s-classValue-p">' % myName)
+ if myElem.complexType is not None:
+ myClassAttr = myElem.complexType.namedAttribute('class')
+ if myClassAttr is not None \
+ and myClassAttr.default is not None:
+ #print 'TRACE: myClassAttr.default: "%s"' % myClassAttr.default
+ for aStr in myClassAttr.default[1:].strip().split():
+ if aStr.find('/') != -1:
+ a,b = aStr.split('/')
+ myS.write(' %s/' % a)
+ myS.write('<keyword>%s</keyword>' % b)
+ self._writeLine(myS, '</p>')
+ self._writeLine(myS, '</section>')
+ self._writeLine(myS, '</refbody>')
+ self._writeLine(myS, '</reference>')
+ self.close(myS)
+
+ ##########################
+ # End: Output
+ ##########################
+
+def main():
+ usage = """usage: %prog [options] file_or_dir
+Takes a XSD file or directory and generates a packagedef.dita file with
+the documentation for the XSD file(s)."""
+ print 'Cmd: %s' % ' '.join(sys.argv)
+ optParser = OptionParser(usage, version='%prog ' + __version__)
+ optParser.add_option("-d", action="store_true", dest="dump", default=False,
+ help="Dump IR (for debugging). [default: %default]")
+ optParser.add_option(
+ "-l", "--loglevel",
+ type="int",
+ dest="loglevel",
+ default=20,
+ help="Log Level (debug=10, info=20, warning=30, error=40, critical=50) [default: %default]"
+ )
+ optParser.add_option("-o", "--out",
+ type="string",
+ dest="output",
+ default=None,
+ help="Output file. [default: %default]")
+#===============================================================================
+# optParser.add_option("-u", "--unittest",
+# action="store_true",
+# dest="unit_test",
+# default=False,
+# help="Execute unit tests. [default: %default]")
+#===============================================================================
+ optParser.add_option("-t", "--title", type="string", dest="title",
+ default='C++ API Reference Content Model Definitions',
+ help="Title for the packagedef.dita. [default: %default]")
+ optParser.add_option("-p", "--prefix", type="string", dest="prefix",
+ default='cxx',
+ help="Prefix, only the elements starting with this will be documented. Use '' for all. [default: %default]")
+ opts, args = optParser.parse_args()
+ clkStart = time.clock()
+ # Initialise logging etc.
+ logging.basicConfig(level=opts.loglevel,
+ format='%(asctime)s %(levelname)-8s %(message)s',
+ #datefmt='%y-%m-%d % %H:%M:%S',
+ stream=sys.stdout)
+#===============================================================================
+# if opts.unit_test:
+# unitTest()
+#===============================================================================
+ if len(args) > 0:
+ # Your code here
+ myX = XsdToPackageDef(opts.prefix)
+ for aFile in args:
+ myX.addXsdPath(aFile)
+ myX.writeToFile(opts.output, opts.title)
+ if opts.dump:
+ myX.dump()
+ else:
+ optParser.print_help()
+ optParser.error("No arguments!")
+ return 1
+ clkExec = time.clock() - clkStart
+ print 'CPU time = %8.3f (S)' % clkExec
+ print 'Bye, bye!'
+ return 0
+
+if __name__ == '__main__':
+ #multiprocessing.freeze_support()
+ sys.exit(main())
+