parent heading number

hi
does anyone have dxl script that gives you the section heading number of the section that the requirement is in?
e.g. 3.2.1 blah
reqt 1
reqt 2

i would like an attribute for the two reqts that has a value '3.2.1'

thanks
arlene
SystemAdmin - Wed Oct 14 09:31:33 EDT 2009

Re: parent heading number
llandale - Wed Oct 14 10:52:53 EDT 2009

To start, you can get a handle on the parent of an object:
oParent = parent(obj)
then perhaps get the 'number' of that object:
string HeadNum = number(oParent)

  • Louie

Re: parent heading number
Peter_Albert - Wed Oct 14 11:04:22 EDT 2009

llandale - Wed Oct 14 10:52:53 EDT 2009
To start, you can get a handle on the parent of an object:
oParent = parent(obj)
then perhaps get the 'number' of that object:
string HeadNum = number(oParent)

  • Louie

The old Telelogic DOORS forum had a lengthy discussion on all possible pitfalls associated to this task. What is left in my collection of scripts is the attached routine provided by Tony Goodman, more or less implementing Louie's proposal.


string sectionNumber(Object o) 
{ Object oParent = 

null 
// heading objects are easy 

if (o.
"Object Heading" 
"" != 
"" && !table(o) && !cell(o)) 
{

return(number(o))
} 
// get parent object oParent = parent(o) 

if (

null oParent) 
{
// text object at top of hierarchy 

return(
"0") 
} 
// recurse 

return(sectionNumber(oParent)) 
}


Regards,

Peter

Re: parent heading number
roybond - Wed Oct 14 11:35:45 EDT 2009

Peter_Albert - Wed Oct 14 11:04:22 EDT 2009
The old Telelogic DOORS forum had a lengthy discussion on all possible pitfalls associated to this task. What is left in my collection of scripts is the attached routine provided by Tony Goodman, more or less implementing Louie's proposal.


string sectionNumber(Object o) 
{ Object oParent = 

null 
// heading objects are easy 

if (o.
"Object Heading" 
"" != 
"" && !table(o) && !cell(o)) 
{

return(number(o))
} 
// get parent object oParent = parent(o) 

if (

null oParent) 
{
// text object at top of hierarchy 

return(
"0") 
} 
// recurse 

return(sectionNumber(oParent)) 
}


Regards,

Peter

I have a similar script which looks for a Parent Object, but given that the immediate Parent may not itself contain a Heading, I have a loop which makes a fixed number of attempts to find the Parent :


Object findSectionHeading (Object o) 
{   

int maxLoop = 5    
// Maximum number of attempts to find a Parent Object with Object Heading text.   string oHead = o.
"Object Heading" 

if (

null oHead) 
{ bool found = 

false 

int i = 0 

while (!found && i != maxLoop) 
{ o = parent o   

if (

null o) 
{   i = maxLoop   
} 

else 
{ oHead = o.
"Object Heading" 

if (!

null oHead) 
{ found = 

true 
} 

else 
{ i++ 
} 
} 
} 
}   

return o 
}


All of this does, of course, assume that the Object structure uses Parent and Child Objects (ie. is not Flat).

Roy.

Re: parent heading number
Peter_Albert - Wed Oct 14 11:39:21 EDT 2009

Peter_Albert - Wed Oct 14 11:04:22 EDT 2009
The old Telelogic DOORS forum had a lengthy discussion on all possible pitfalls associated to this task. What is left in my collection of scripts is the attached routine provided by Tony Goodman, more or less implementing Louie's proposal.


string sectionNumber(Object o) 
{ Object oParent = 

null 
// heading objects are easy 

if (o.
"Object Heading" 
"" != 
"" && !table(o) && !cell(o)) 
{

return(number(o))
} 
// get parent object oParent = parent(o) 

if (

null oParent) 
{
// text object at top of hierarchy 

return(
"0") 
} 
// recurse 

return(sectionNumber(oParent)) 
}


Regards,

Peter

I should have pointed out that Tony's script is a recursive script, i.e. it will report the section number of the first (grand-) parent object it will find above the calling object; not restricted to the level directly above.

Regards,

Peter

Re: parent heading number
kierant - Thu Oct 15 08:16:41 EDT 2009

Hi - Rather than manually going up through hierarchy, might it not be feasible to take the object number that Doors automatically maintains on each object and parse this to derive the section nr? I may have misunderstood the problem (and will happily defer to greater Doors skills of earlier contributors), but we created a DXL attribute using below - it basically looks for "0-" in the object number as the section nr will precede that.

Kieran

Buffer onr = create
Buffer result = create
Buffer temp = create
onr = number(obj)
string marker = "0-"
int locn = 0
locn = contains(onr,marker,1)
if (locn >1) {
locn = locn -2
result = "Section " onr 0:locn

} else {
result += "Section "
result += onr0:
}
obj.attrDXLName = result

Re: parent heading number
llandale - Thu Oct 15 12:42:37 EDT 2009

kierant - Thu Oct 15 08:16:41 EDT 2009
Hi - Rather than manually going up through hierarchy, might it not be feasible to take the object number that Doors automatically maintains on each object and parse this to derive the section nr? I may have misunderstood the problem (and will happily defer to greater Doors skills of earlier contributors), but we created a DXL attribute using below - it basically looks for "0-" in the object number as the section nr will precede that.

Kieran

Buffer onr = create
Buffer result = create
Buffer temp = create
onr = number(obj)
string marker = "0-"
int locn = 0
locn = contains(onr,marker,1)
if (locn >1) {
locn = locn -2
result = "Section " onr 0:locn

} else {
result += "Section "
result += onr0:
}
obj.attrDXLName = result

Be sure to test this with section numbers containing more than one 0-. This happens in tables, but also happens when a text object has children.

Without thinking about it much: I'd say start peeling away from the right side of the 'number' getting rid of any ".0-nn", until you don't find any more.

  • Louie

Re: parent heading number
moonray - Tue Oct 20 08:06:43 EDT 2009

Arlene,
Here's yet another variation which works well for me. This function uses recursion and relies on consistent separation of text in the Object Heading and Object Text attributes:

Object getparentheading (Object o)
{
if (o == null) return null
Object po = parent(o)
if (po != null and po."Object Heading" == "")
{
po = parent po
getparentheading po
}
return po
}

Re: parent heading number
llandale - Tue Oct 20 14:45:43 EDT 2009

moonray - Tue Oct 20 08:06:43 EDT 2009
Arlene,
Here's yet another variation which works well for me. This function uses recursion and relies on consistent separation of text in the Object Heading and Object Text attributes:

Object getparentheading (Object o)
{
if (o == null) return null
Object po = parent(o)
if (po != null and po."Object Heading" == "")
{
po = parent po
getparentheading po
}
return po
}

po = parent po
getparentheading po

should be just:
po = getparentheading(po)

Also, an empty DOORS object is (strangely) considered a heading in DOORS. Thus its a heading when o."Object Heading" is not null, or when o."Object Text" is null and there is no 'picture' and there is no OLE in the Object text in the object. I don't recall the exact rules regarding empty invisible rich text markup in Object Text. And, of course, table/row/cell objects are not allowed to be headings, even when they have Object Heading.

Forget all that. Parse the paragraph 'number' of the object to determine whether its a heading.

  • Louie

Re: parent heading number
moonray - Wed Oct 21 08:11:23 EDT 2009

llandale - Tue Oct 20 14:45:43 EDT 2009
po = parent po
getparentheading po

should be just:
po = getparentheading(po)

Also, an empty DOORS object is (strangely) considered a heading in DOORS. Thus its a heading when o."Object Heading" is not null, or when o."Object Text" is null and there is no 'picture' and there is no OLE in the Object text in the object. I don't recall the exact rules regarding empty invisible rich text markup in Object Text. And, of course, table/row/cell objects are not allowed to be headings, even when they have Object Heading.

Forget all that. Parse the paragraph 'number' of the object to determine whether its a heading.

  • Louie

Louie,
I used your abbreviated po = getparentheading(po) while bringing up my function and spent a few hours figuring out why it wouldn't recurse properly. I ended up with the format as originally listed, which works for me in all normal cases. I attribute the non-functionality of the abbreviated form to a DOORS internal bug under recursion, and didn't have time to pursue it any further.

Re: parent heading number
llandale - Thu Oct 22 15:17:04 EDT 2009

moonray - Wed Oct 21 08:11:23 EDT 2009
Louie,
I used your abbreviated po = getparentheading(po) while bringing up my function and spent a few hours figuring out why it wouldn't recurse properly. I ended up with the format as originally listed, which works for me in all normal cases. I attribute the non-functionality of the abbreviated form to a DOORS internal bug under recursion, and didn't have time to pursue it any further.

Sorry, perhaps you posted the wrong thing, but what you posted could not possibly work, which was this:

Object getparentheading (Object o) 
{ 

if (o == 

null) 

return 

null Object po = parent(o) 

if (po != 

null and po.
"Object Heading" == 
"") 
{ po = parent po getparentheading po 
} 

return po 
}

[1] You have an interpret error in line 5 where you compare an attr reference to a null string:

This: 

if (po != 

null and po.
"Object Heading" == 
"") should be changed to: 

if (po != 

null and po.
"Object Heading" 
"" == 
"")

[2] you are invoking your function recursively, but not assigning the returned Object to anything:

This: getparentheading po must surely be changed to something like 

this: oResult = getparentheading po


Your code will find the heading if its the next higher object (a normal spec layout), but will otherwise return the one 2 levels higher regardless of whether its a heading.

Well, my suggestion didn't work either.

Try this:
o Display object level and object number.
o Create a module with a long list of text objects 'below' each other: hit cntl-L a few times, then edit each object and insert Text cntl-t.
o Add Heading to the first object.
o Create a new heading 'after' the first object cntl-N, then add heading.
o Insert a table 'below' that new heading.

Select one of the lower objects and run the below. Notice your function finds a text object, but mine (new code) finds the first object. Select a table cell. Notice your function finds the table object but mine finds the heading.

Object getparentheadingMoonray(Object o) 
{ 

if (

null o) print 
">>getMoonray: null(o)\n" 

else print 
">>getMoonray: " identifier(o) 
"\n"   

if (o == 

null) 

return 

null Object po = parent(o) 

if (po != 

null and po.
"Object Heading" 
"" == 
"") 
{ po = parent po getparentheadingMoonray(po) 
} 

return po 
} 
// end getparentheadingMoonray()     Object getparentheadingLandale(Object o) 
{ 

if (

null o) print 
">>getLandale: null(o)\n" 

else print 
">>getLandale: " identifier(o) 
"\n"   

if (o == 

null) 

return(

null)   Object po = parent(o)   

if (po == 

null) 
{
}       
// nothing to do elseif(po.
"Object Heading" 
"" != 
"")
{
} 
// This is a heading, nothing to do 

else   po = getparentheadingLandale(po)   

return po 
}  
// end getparentheadingLandale()     

void     Driver(Object oCurr) 
{ Object      oMoonray = getparentheadingMoonray(oCurr) Object        oLandale = getparentheadingLandale(oCurr)   print 
"** " identifier(oCurr) 
"\t" number(oCurr) 
"\thas parents:\n"   

if (

null oMoonray) print 
"\tMoonray: \tnull(parent)\n" 

else print 
"\tMoonray: \t" identifier(oMoonray) 
"\t" number(oMoonray) 
"\n"     

if (

null oLandale) print 
"\tLandale: \tnull(parent)\n" 

else print 
"\tLandale: \t" identifier(oLandale) 
"\t" number(oLandale) 
"\n"   
}      
// end Driver()   Driver(current Object)  
// **** MAIN ****


Even my function is inadequate, since empty objects are indeed considered 'headings' by DOORS, as evidenced by the fact they display their number in the main column. As I recall, a DOORS 'Heading' is an object either containing non-null raw Heading or containing no raw Text, no Ole in the Text, and no Picture. Somewhere along the way I found some obscure exception to even that (perhaps it had to do with invisible rich text), and then I gave up and went with the parse-the-number method. Below is my function "fIsHead" which determines if the specified object is considered a 'heading' by DOORS. use fIsHead instead of checking null Object Heading in my function above.


// Following buffer is local to fIsHead() Buffer  gl_bufIsHeadNum = create(32) 
//*********************** bool      fIsHead(Object obj) 
{      
// Does DOORS consider the object a 'Heading' object? 
// Heading Objects are those that display the paragraph number in the Main column in DOORS 
// DOORS considerations for determining 'Heading Objects': 
//     [a] Objects that contain some non-null rich Heading text. 
//     [b] Objects that have no non-null rich Object Text and no Pictures (i.e. empty objects) 
//       [c] However, Cell, row header, and table header objects are NEVER headings, 
//       even when they contain Object Heading or are empty. 
//       [d] Note that invisible rich-text markup only is considered. 
// This function looks at the Paragraph number of the object to determine if 
//      DOORS considers it a Heading.   
// Notes: 
// [1]  Normal Text Object Paragraph Numbers have a ZeroDash and look like this: 3.2.1.0-4. 
//      Notice there is a dash after the last period. 
// [2]  Normal Headings Numbers have no dash and look like: 3.2.1. 
// [3]  When a Heading is (incorrectly) a child of a Text Object, its Para looks like this: 
//      3.2.1.0-4.2; notice there is a period after the last dash. 
// [4]  Level 1 Headings paragraphs have no dashes nor periods, and look like "1". 
// [5]  Level 1 Text paragraphs have no periods, but do contain a dash, and look like "0-1". 
// [6]  Objects in tables (cell, row, table) have para numbers like nested text objects: 3-2.0-1.0-1. 
//      This function would correctly identifies them as Text without an explicit check, 
//      but to save time and string table space a specific table-row-cell check is made.   
// Strategy: Get the paragraph 'number' of the object.   
//    If its in a table its not a Heading 
//   If it contains no dash then its a heading. 
//    If it has a dash but there is a period following the last dash, then its a heading. 
//   Otherwise (there's a dash with no period after it) then its not a Heading object.   

if (

null obj)                 

return(

false)   

int     LocDash, LocDashLast, LocDashNext, LocPeriod    
// Locations in the paragraph number   

if (row(obj) or table(obj) or cell(obj)) 

return(

false)    
// Table-Row-Cell objects are not Headings.   gl_bufIsHeadNum       = number(obj)   
// Put the Paragraph in the buffer LocDash               = contains(gl_bufIsHeadNum, 
'-', 0) 

if (LocDash < 0)      

return(

true)  
// No dashes at all, must be a heading (e.g. "2" or "3.2.1")   
// Find the last dash in the Paragraph Number LocDashLast = LocDash LocDashNext = LocDash 

while (LocDashNext > 0) 
{  LocDashNext         = contains(gl_bufIsHeadNum, 
'-', LocDashLast+1) 
// print "\t" tempStringOf(gl_bufIsHeadNum) "\t" LocDash "\t" LocDashNext "\n" 

if (LocDashNext > 0) LocDashLast = LocDashNext 
} 
// Find any period after the last dash: LocPeriod      = contains(gl_bufIsHeadNum, 
'.', LocDashLast+1) 
// print "fIsHead\t" (stringOf(gl_bufIsHeadNum)) "\t" LocDash "\t" LocPeriod "\n" 

return(LocPeriod > LocDashLast)  
// Its a heading if there's a period after the last Dash 
}  
// end fIsHead()


  • Louie