This script moves objects into a proper hierarchy after import from spreadsheet. Assumes that the “main” column in the spreadsheet that contains object text is prefixed with a paragraph number for heading objects. The first object in the module must be a level one object. This paragraph number is parsed and used to determine the level of the object in the hierarchy. These paragraph numbers are removed and the remaining text is moved into the Object Heading.
// Build Hierarchy after import from spreadsheet /* Description: Moves objects into a proper hierarchy after import from spreadsheet. Assumes that the "main" column in the spreadsheet that contains object text is prefixed with a paragraph number for heading objects. The first object in the module must be a level one object. This paragraph number is parsed and used to determine the level of the object in the hierarchy. These paragraph numbers are removed and the remaining text is moved into the Object Heading. smartdxl.com */ pragma runLim, 0 const string ATTR_LEVEL_INDICATOR = "Object Text" const string ATTR_NEW_LEVEL = "New Level" /************************************ createLevelAttr ************************************/ void createLevelAttr(Module m) { AttrDef ad = null (current ModuleRef__) = m if (!exists attribute ATTR_NEW_LEVEL) { ad = create(object type "Integer" attribute ATTR_NEW_LEVEL) } } /************************************ flattenHierarchy ************************************/ string flattenHierarchy(Module m) { Object o = null Object oFirst = null Object oPrev = null int count = 0 Skip objects = create oFirst = first(m) if (null oFirst || level(oFirst) != 1) { return("Module must begin with a level 1 object") } showExplorer(false) showTables(false) for o in m do { put(objects, count++, o) } for o in objects do { if (o == oFirst) { oPrev = o } else { //print("move " identifier(o) " after " identifier(oPrev) "\n") move(o, oPrev) oPrev = o } } delete(objects) return("") } /************************************ getLevel Returns the proposed level of the object based on the contents of its Object Text. If the object text is empty or does not start with a digit then a level of zero is returned. Otherwise the level returned is based on the number of digits separated by periods that are found at the beginnign of the object text. ************************************/ int getLevel(Object o) { string s = "" string levelString = "" int len = 0 int i = 0 int depth = 0 s = o.ATTR_LEVEL_INDICATOR "" len = length(s) // empty string, return zero if (len == 0) { return(0) } // does not start with a number, return zero if (!isdigit(s[0])) { return(0) } // extract the legal number from the beginning of the // string. Add an extra period at the end to make the next bit easier for (i = 0; i < len; i++) { if (s[i] != '.' && !isdigit(s[i])) { levelString = s[0:i-1] "." break } } // count the periods to determine the depth for (i = 0; i < length(levelString); i++) { if (levelString[i] == '.') depth++ } return(depth) } /************************************ getHeading ************************************/ string getHeading(string s) { int len = 0 int i = 0 len = length(s) for (i = 0; i < len; i++) { if (isalpha(s[i])) { return(s[i:]) } } return(s) } /************************************ setInitialLevel populate level new level attribute based on contents of level indicator attribute (usually object text) ************************************/ void setInitialLevel(Module m) { Object o = null for o in m do { o.ATTR_NEW_LEVEL = getLevel(o) } } /************************************ refineLevels change new level attribute for objects with new level of zero. If new level attribute is zero then set it to level below previous object that had a non-zero level. ************************************/ void refineLevels(Module m) { Object o = null int prevLevel = 0 int thisLevel = 0 for o in m do { thisLevel = o.ATTR_NEW_LEVEL if (thisLevel == 0) { o.ATTR_NEW_LEVEL = prevLevel + 1 } else { o."Object Heading" = getHeading(o."Object Text" "") o."Object Text" = "" prevLevel = thisLevel } } } /************************************ moveObjects ************************************/ void moveObjects(Object oParent) { } /************************************ moveObjects ************************************/ void moveObjects(Module m) { Object o = null Object oParent = null int prevLevel = 0 int thisLevel = 0 int count = 0 int l = 0 int maxLevel = 0 Skip objects = create for o in m do { put(objects, count++, o) } for o in objects do { thisLevel = o.ATTR_NEW_LEVEL if (thisLevel > maxLevel) { maxLevel = thisLevel } } for (l = maxLevel; l > 1; l--) { for o in objects do { thisLevel = o.ATTR_NEW_LEVEL if (thisLevel == l - 1) { oParent = o } else if (thisLevel == l) { move(o, last below oParent) } } } delete(objects) } /************************************ MAIN ************************************/ Module currModule = current Module string res = "" if (!isEdit(currModule)) { infoBox("This utility can only be run in exclusive edit mode") halt } // check that the required level indicator attribute exists createLevelAttr(currModule) // ensure flat module hierarchy before starting - i.e. all objects at level 1 res = flattenHierarchy(currModule) if (res != "") { infoBox(res) halt } setInitialLevel(currModule) refineLevels(currModule) moveObjects(currModule)