checking an object in a nested link via dxl - ibm-doors

I have the following situation.
I want to count in Module 1, how many objects are having links in links from Module 3.
example:
Module 1 Obj1 <- Module 2 Obj1 <- Module 3.Obj1
Module 1 Obj2 <- Module 2 Obj1 <- Module 3.Obj1
Module 1 Obj3 <- Module 2 Obj1 <- Module 3.Obj1
Module 1 Obj4 <- Module 2 Obj1
Module 1 Obj5 <- Module 2 Obj1
The count should return 3, in the above case.
Is it possible via DXL to follow a link, and then follow another link?
(not using the Wizard or DXL attributes)
Most important for me: knowing if somebody else did this and it's possible to do.

Please try the following DXL from within the module that has the incoming links. Before running the code:
make sure that you open the 'Edit DXL' window from the relevant module
set the string values assigned to global constant STR_LINK_MOD_FULLNAME (line 17) to the full pathname of the link module whose links you are interested in
set the string values assigned to global constant STR_SRC_MOD_FULLNAME (line 18) to the full pathname of the source formal module (Module 3, in your example) whose links you are interested in
You shouldn't need to change anything else to make it work.
N.B. I have not considered the implications of analysing links in all link modules by using the string "*" in place of a specific link module name in line 17 (see point 2, above).
I also haven't gone out of my way to explain the code, though I have tried to be nice and tidy up after myself where DOORS and DXL require it. Please feel free to reply with any questions on what I have done.
Kind regards,
Richard
//<CheckObjectInNestedLink.dxl>
/*
*/
///////////////
// Sanity check
if (null (current Module))
{
print "ERROR: this script must be run from a Formal Module."
}
///////////////////
// Global Constants
const string STR_LINK_MOD_FULLNAME = "/New Family Car Project/Admin/Satisfies" // the fullName of a single link module - results of using "*" have not been considered/tested
const string STR_SRC_MOD_FULLNAME = "/New Family Car Project/Architecture/Architectural Design" // The fullName of the desired source Formal Module
///////////////////
// Global Variables
Module modSource = null
Object objTarget = null
Object objSource = null
Link lkIn = null
Skip skLinkedMods = create()
Skip skObjsWithDesiredSource = create()
int intNoOfLinked = 0
//////////////////////
// Auxiliary Functions
void closeSourceMods ()
{
Module srcMod
for srcMod in skLinkedMods do
{
close(srcMod)
}
}
void openSourceMods (Object objWithLinks)
{
ModName_ srcModRef
Module srcMod
for srcModRef in (objWithLinks <- STR_LINK_MOD_FULLNAME) do
{
srcMod = read(fullName(srcModRef), false)
put(skLinkedMods, srcMod, srcMod)
}
}
void recurseFollowInLinks (Object objWithLinks)
{
openSourceMods(objWithLinks)
for lkIn in objWithLinks <- STR_LINK_MOD_FULLNAME do
{
openSourceMods(objWithLinks)
objSource = source(lkIn)
string strSrcModName = fullName(module(objSource))
if (strSrcModName == STR_SRC_MOD_FULLNAME)
{
bool blNewEntry = put(skObjsWithDesiredSource, objTarget, objTarget)
if (blNewEntry)
{
intNoOfLinked++
}
//print "put(skObjsWithDesiredSource, " identifier(objTarget) ", " identifier(objTarget) ")\n"
}
recurseFollowInLinks(objSource)
}
}
void checkObjectInNestedLink (Module modThis, string strSourceModuleFullname, string strLinkModuleFullName)
{
intNoOfLinked = 0
for objTarget in modThis do
{
recurseFollowInLinks(objTarget)
}
print "The following " intNoOfLinked " objects have direct or indirect links of type " STR_LINK_MOD_FULLNAME " from formal module " STR_SRC_MOD_FULLNAME ":\n"
for objTarget in skObjsWithDesiredSource do
{
print identifier(objTarget)
print "\n"
}
}
///////////////
// Main Program
checkObjectInNestedLink ((current Module), STR_SRC_MOD_FULLNAME, STR_LINK_MOD_FULLNAME)
closeSourceMods()
delete(skLinkedMods)
delete(skObjsWithDesiredSource)

Related

performance issue with getProperties

I‘m new to this so I hope I get it right.
I‘m not exactly new to writing DXL but currently have a performance issue with calling getProperties from a Layout dxl column that is supposed to display outgoing links depending on a module attribute value of type Enum of the linked module.
The code basically works but takes extremely long to complete. Commenting out the getProperties call makes it as fast as it could be.
Yes, the call is written exactly as shown in DXL Ref manual.
Calling the attribute directly, using a module object and dot operator does not work either as it always returns the enums default value but not the actual.
Any ideas welcome...
EDIT added example code below
// couple of declarations snipped
string cond = "Enum selection here" // this is modified from actual code, to show the idea
string linkModName = "*"
ModuleProperties mp
for l in all(o->linkModName) do
{
otherVersion = targetVersion l
otherMod = module(otherVersion)
if (null otherMod || isDeleted otherMod) continue
othero = target l
if (null othero)
{
load(otherVersion,false)
}
getProperties(otherVersion, mp)
sTemp = mp.myAttr
if (sTemp == cond) continue
// further code snipped
}
I'm not 100% sure but I think there is/was a performance issue with module properties in some DOORS versions.
You might want to try the following, i.e. directly get the attribute from the loaded Module
[...]
othero = target l
Module m
if (null othero)
{
m = load(otherVersion,false)
} else {
m = module othero
}
sTemp = m.myAttr
[...]
Caution, I did not test this snippet.

How to get object and lower hierarchical objects from a DXL

I'm new on DXL and working on something that is probably quite simple.
I would like to parse the current module, and get the following data for each object that has a given ID (calling IDNUM below) not empty:
IDNUM - Object text - all text with a lower hierarchic level and the same thing for all objects liked to this one.
It will probably be easier to understand with the code. So far, it looks like that:
Object o
Object ol
Link l
Module m = current Module
For o in entire(m) do{
if (o."IDNUM" != ""){
print o."IDNUM" ""
print o."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN o
for l in o --> "*" do{
ol = target(l)
print ol."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN ol
}
}
}
Basically, I have the ID and title of both an object and the one liked to it, but not the text below. In other words, my code will "mimic" the function right click>copy>copy with hierarchy
How can I do that? Unfortunately I didn't find anything very helpful.
Thanks a lot in advance,
Here is the sketch code you outlined:
Object o
Object ol
Link l
Module m = current Module
For o in entire(m) do{
if (o."IDNUM" != ""){
print o."IDNUM" ""
print o."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN o
for l in o --> "*" do{
ol = target(l)
print ol."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN ol
}
}
}
There are a few little syntax things that need to be changed here, but the big change is how you are handling linked items. Links 'live' in the source module, but they only store a limited amount of information, mostly the modules that are the source and target of the link, and the absolute numbers of the objects they touch. So you need to check if the module on the other side is open before you try and read text from it.
And since you are trying to go through the entire link structure, you'll need a recursive element to this.
I would probably end up with something like this:
//turn off run limit timer- this might take a bit
pragma runLim , 0
Object o
Module m = current Module
// Recursive function- assumes each object has a text attribute- will error otherwise
void link_print(Object obj) {
print obj."text" "\n"
Link out_link
Object next_obj = null
for out_link in obj -> "*" do {
// Set the next object in the chain
next_obj = target ( out_link )
// This might return null if the module is not loaded
if ( null next_obj ) {
// Load the module in read-only mode, displayed and in standard view
read ( fullName ( ModName_ target ( out_link ) ) , true , true )
// Try and resolve out 'target' again
next_obj = target ( out_link )
// If it doesn't work, print a message so we can figure it out
if ( null next_obj ) {
print "Error Accessing Object " ( targetAbsNo ( out_link ) )""
} else {
//Iterate down structure
link_print ( next_obj )
}
} else {
//Iterate down structure
link_print ( next_obj )
}
}
}
for o in entire(m) do {
// Note that I cast the result of o."IDNUM" to a string type by appending ""
if (o."IDNUM" "" != ""){
print o."IDNUM" "\n"
// Recurse
link_print(o)
print "\n"
}
}
Note! Depending on the size of your link structure, i.e. how many levels you have (and if there are any circular link patterns), this could be a pretty resource intensive task, and would be better solved using something other than "print" commands (like appending it to a word file, for example, so you know how far it got before it errored out)
Good luck!
EDIT:
Rather than head down recursively, this script will now go a single level but should report child objects.
//turn off run limit timer- this might take a bit
pragma runLim , 0
Object o
Module m = current Module
// Recursive function- assumes each object has a text attribute- will error otherwise
void link_print(Object obj) {
print obj."text" "\n"
Link out_link
Object next_obj = null
Object child_obj = null
for out_link in obj -> "*" do {
// Set the next object in the chain
next_obj = target ( out_link )
// This might return null if the module is not loaded
if ( null next_obj ) {
// Load the module in read-only mode, displayed and in standard view
read ( fullName ( ModName_ target ( out_link ) ) , true , true )
// Try and resolve out 'target' again
next_obj = target ( out_link )
// If it doesn't work, print a message so we can figure it out
if ( null next_obj ) {
print "Error Accessing Object " ( targetAbsNo ( out_link ) )""
} else {
// Loop and report on child objects
for child_obj in next_obj do {
print child_obj."text" "\n"
}
}
} else {
// Loop and report on child objects
for child_obj in next_obj do {
print child_obj."text" "\n"
}
}
}
}
for o in entire(m) do {
// Note that I cast the result of o."IDNUM" to a string type by appending ""
if (o."IDNUM" "" != ""){
print o."IDNUM" "\n"
// Recurse
link_print(o)
print "\n"
}
}
Dear Russell (and everyone else)
I've just went through the piece of code you provided me and it works.... but not for what I'm looking for. It seems my explanation wasn't very clear. I'm sorry (I'm not a native speaker).
I'm not looking to get all links, but just the Object text that is written just below the object pointed by the current link.
Here is what my files look like
object1 (with IDNUM) : "Title_doc_1" --> (link) objectA "Title_doc_2"
object2 : "some_text" objectB : "some_text"
object3 : "some_text" objectC : "some_text"
(object1 can point to many other objectA but I already deal with that.)
The code I provided above parses the "doc_1", and print "IDNUM" "Title_doc_1" "Title_doc_2"
What I'm looking for is to get, not only objectA but also objectB and objectC which are hierarchically below objectA (and object2 and object3 too but it will ve the same process).
Hopping I made myself understood...

DOORS Layout DXL is reporting each link twice

I'm using the Analysis Wizard to create a LayoutDXL column which should list attributes (e.g. AbsoluteNumber) for each existing In-link in my current module. In one particular DOORS module, the resulting DXL code displays each of these attributes twice. This doesn't happen in other modules.
I did notice that the offending module doesn't have a defined set of LinkModules (as seen in File/ModuleProperties). Could that be causing some sort of loopback?
Update:
I've discovered that somehow the DXL code "thinks" there are two versions of a defined LinkModule, i.e. "Current" and "Baseline X" . These each link to different baseline numbers in the target DOORS module. I don't know how to fix that.
For reference, here's the DXL code generated with the Wizard. This is DOORS 9.6.1.11
// DXL generated by DOORS traceability wizard on 12 February 2019.
// Wizard version 2.0, DOORS version 9.6.1.11
pragma runLim, 0
string limitModules[1] = {"[serial number redacted]"}
void showIn(Object o, int depth) {
Link l
LinkRef lr
ModName_ otherMod = null
Module linkMod = null
ModuleVersion otherVersion = null
Object othero
string disp = null
string s = null
string plain, plainDisp
int plainTextLen
int count
bool doneOne = false
string linkModName = "*"
for lr in all(o<-linkModName) do {
otherMod = module (sourceVersion lr)
if (!null otherMod) {
if ((!isDeleted otherMod) && (null data(sourceVersion lr))) {
if (!equal(getItem otherMod, (itemFromID limitModules[depth-1]))) continue
load((sourceVersion lr),false)
}
}
}
for l in all(o<-linkModName) do {
otherVersion = sourceVersion l
otherMod = module(otherVersion)
if (null otherMod || isDeleted otherMod) continue
if (!equal(getItem otherMod, (itemFromID limitModules[depth-1]))) continue
othero = source l
if (null othero) {
load(otherVersion,false)
}
othero = source l
if (null othero) continue
if (isDeleted othero) continue
doneOne = true
if (depth == 1) {
s = probeRichAttr_(othero,"Absolute Number", false)
if (s == "")
displayRich("\\pard " " ")
else
displayRich("\\pard " s)
s = probeRichAttr_(othero,"Object Heading", false)
if (s == "")
displayRich("\\pard " " ")
else
displayRich("\\pard " s)
}
}
}
showIn(obj,1)
I've seen the situation where objects DID have two links between them, this is possible with different link modules (Object 1 of Module A SATISFIES Object 2 of Module B and Object 1 of Module A REFINES Object 2 of Module B). While there may be reasons for such a situation, most often this is caused by a "link move" script that was not used correctly.
You should augment your code by displaying the name of the link module as well (variable linkModName). Perhaps this shows the reason for your observation

DXL open a module

Basically I would need a script(or function) that would look after a module (using it's name as a parameter),within a database and not projects, and return the module as it is for further operations on it.
I am using DOORS 9.3
Something like this should get you started:
Item i
Folder f = folder("/")
Folder f2
void drill_items(Folder f) {
for i in f do {
if(type(i) "" == "Formal")
\\ Do some logic here to check if its the module you are looking for.
\\ If you find it, break out and return the Module handle.
else if((type(i) "" == "Project") || (type(i) "" == "Folder")) {
f2 = folder(fullName(i) "")
drill_items(f2)
}
}
}
drill_items(f)
You could write something using a regular expression to compare some input to the module name to find the one you are looking for.
-Steve

parseDeftemplate in Jess application. Can't provide the JessTokenStream

I'm implementing a methond in my application that uses the Jessp parser class in order to open a file and getting the deftemplates and deffacts inside of it. The problem is that when trying to obtain the result into a object variable, it asks on the constructor for a JessTokenStream. I tried to pass a JessToken, but then it complains about the type, that it should be e8. Searched through the Jess documentation but didn't found an explanation for the arguments, only the syntax of the constructor.
Anyone can help?.
Thanks in advance!!!
The class JessTokenStream is not public, so you can't actually call those parseXXX() methods. They are public for historical reasons but aren't actually usable by clients. They should actually be removed from the public interface.
Instead, use the two-argument form of parseExpression(), and then test the returned object to determine its type. Then you can do what you want with the returned object:
Rete engine = ...
Jesp jesp = ...
Object o = jesp.parseExpression(engine.getGlobalContext(), false);
if (o instanceof Deffacts) {
Deffacts d = (Deffacts) o;
for (int i = 0; i<d.getNFacts(); ++i) {
Fact f = d.getFact(i);
Deftemplate t = f.getDeftemplate();
System.out.println("Fact name is " + f.getName();
System.out.println("Fact name is " + f.getName();
for (String name: t.getSlotNames())
System.out.println("Slot " + name + " contains " + f.getSlotValue(name));
}
}

Resources