Author Topic: How do I get attributes nested within an xref?  (Read 6969 times)

0 Members and 1 Guest are viewing this topic.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
How do I get attributes nested within an xref?
« on: February 17, 2008, 02:47:53 PM »
I received a PM from a kindly member of our swamp collective; an inquiry that went something like this --

Quote
I was hoping to find out how to programatically (autolisp) :
• get into the refedit command
• snatch some attribute values from a title block
• exit the refedit command making no changes.

Subsequent detail (rephrased) --

Quote
For example, a host dwg might reference "ParentDrawing.dwg" on several layouts, thus each layout will have 1 instance of the "ParentDrawing" xref.

The xref drawing file hosts a block named "ChildBlock", which in turn hosts the attributes I'm interested in retrieving.

Here's one possible way --

Code: [Select]
(defun _FindFooInCollection ( collection foo / result )

[color=green]    ;;  Aside from being a function what foo is THIS function
    ;;  cares not. All foo has to do is take one argument, an
    ;;  object. If it returns a non nil value iteration of the
    ;;  collection will halt immediately, and the object that
    ;;  yielded the non nil result by way of foo will be returned,
    ;;  else nil. Caller is charged with the responsibility to
    ;;  pass a legit collection and properly formed function.
    ;;  Passing bad arguments return nil (because of the error
    ;;  trapping) which is misleading so call appropriately. [/color]
   
    (vl-catch-all-apply
       '(lambda ( )
            (vlax-for object collection
                (if (foo object)
                    (progn
                        (setq result object)
                        (exit)
                    )
                )       
            )
        )
    )   
   
    result
   
)

Code: [Select]
(defun _Item ( collection name / result )

[color=green]    ;;  Get the item named named from the collection. If the name
    ;;  doesn't exist nothing is returned. Caller is charged with
    ;;  the responsibility to pass legit data. Passing a bogus
    ;;  collection object will return nil (because of the error
    ;;  trapping) which can be misleading, so call appropriately.[/color]
   
    (vl-catch-all-apply
       '(lambda ( )
            (setq result
                (vla-item
                    collection
                    name
                )
            )
        )
    )
   
    result
   
)

Code: [Select]
(defun _GetXrefAttributes ( document parentBlockName childBlockName / parentBlock childBlock )

[color=green]    ;;  Given the name of an xref, and the name of a block nested
    ;;  therein, retrieve the attributes (if found) as a list, in
    ;;  the form ((tag value)(tag vale) ... (tag value)). This
    ;;  assumes a nested block within the xref, rather than the
    ;;  attributes simply residing in the xref's modelspace, which
    ;;  would be doubtful, since they would not be rendered in a
    ;;  desirable manner in the parent / host drawing. Make sense?[/color]

    (setq childBlockName (strcase (strcat parentBlockName "|" childBlockName)))

    (if (setq parentBlock (_Item (vla-get-blocks document) parentBlockName))
   
        (if
       
            (setq childBlock
                (_FindFooInCollection
                    parentBlock
                    (lambda ( object )
                        (and
                            (eq "AcDbBlockReference" (vla-get-objectname object))
                            (eq (strcase (vla-get-name object)) childBlockName)
                            (eq :vlax-true (vla-get-hasattributes object))
                        )                     
                    )
                )
            )
           
            (mapcar
               '(lambda ( attribute )
                    (mapcar
                       '(lambda ( property ) (vlax-get attribute property))
                       '(TagString TextString)
                    )
                )   
                (vlax-invoke childBlock 'GetAttributes)
            )
        )   
    )
)

Code: [Select]
[color=green];;  Example[/color]

(_GetXrefAttributes

    (vla-get-activedocument (vlax-get-acad-object))

    "ParentDrawing"

    "ChildBlock"

)

[color=green];;  Might return ...[/color]

(
    ("TAG1" "value1")
    ("TAG2" "value2")
    ("TAG3" "value3")
    ("TAG4" "value4")
    ("TAG5" "value5")
)

Having provided the above there was a small, but significant note by the author --

Quote
Contrary to my earlier post, I think I would like to be able to edit the attributes and have the changes saved back to the original drawing.

This requires a different course of action to take compared to the one required when one wants to simply read the nested attribute values.

One way is to open the XREF drawing by Object DBX, find the block instance in question, grab the attributes, modify them to suit, and then save the parent ObjectDBX document.

Perhaps I'll code that another time. In the interim, I thought the above might prove useful.

:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

adalea03

  • Guest
Re: How do I get attributes nested within an xref?
« Reply #1 on: February 17, 2008, 03:16:01 PM »
MP,
  Toooo... sweet!
  Implementation was a snap.
Code: [Select]
(_getxrefattributes
  (vla-get-activedocument (vlax-get-acad-object))
  "0.2 TITLEBLOCK"
  "BORDERDATA")
;;return> (("JOB_NUMBER" "LE-2008-114") ("PREFIX" "LE") ("DATE" "02.20.08") ("NUMBER_OF_SHEETS" "6")
;;               ("ADDRESS_01" "BGFHSG") ("ADDRESS_02" "HFGFJHDJYT") ("ADDRESS_03" "JHEJGJJYTE")    ("ADDRESS_04" "FHDHTY")
;;               ("RVDATE_01" "02.18.05") ("REASON_01" "FOR APPROVAL") ("RV_DATE_02" "") ("REASON_02" "")
;;               ("RV_DATE_03" "") ("REASON_03" "") ("RV_DATE_04" "") ("REASON_04" "")
;;               ("RV_DATE_05" "") ("REASON_05" "") ("RV_DATE_06" "") ("REASON_06" ""))
I think I can handle the refedit and save.
I am much closer to my goal thanks to you and a misunderstood post.
Hope you are getting closer to yours, if you know what I mean.
I'm eager to get back to the vlide, so before I go, Thank you very much, Michael.
Tony


MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: How do I get attributes nested within an xref?
« Reply #2 on: February 17, 2008, 03:19:55 PM »
Fully my pleasure Tony. Sincere thanks for the opportunity to help and the inspiration.

:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: How do I get attributes nested within an xref?
« Reply #3 on: February 17, 2008, 03:27:03 PM »
I should note that the vanilla (DXF) solution is more succinct but I wanted to post a strictly Visual LISP solution.

:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

T.Willey

  • Needs a day job
  • Posts: 5251
Re: How do I get attributes nested within an xref?
« Reply #4 on: February 18, 2008, 11:01:31 AM »
You can't edit attributes or text via ObjectDBX with Lisp, without the alignment going awol if the objects justification is not left.  Once you change them, you have to open the drawing and do a regen, or move the block that the attributes are associated with before the alignment fixes itself.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

adalea03

  • Guest
Re: How do I get attributes nested within an xref?
« Reply #5 on: February 18, 2008, 01:47:40 PM »
Thanks for the tip, Tim.
My border and its atts are only one level deep in the xref,
so I tried the -refedit command. The syntax was tricky but, I got it to work
without negative results.

Tony

T.Willey

  • Needs a day job
  • Posts: 5251
Re: How do I get attributes nested within an xref?
« Reply #6 on: February 18, 2008, 02:37:59 PM »
Good to hear Tony.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: How do I get attributes nested within an xref?
« Reply #7 on: February 18, 2008, 05:23:16 PM »
You can't edit attributes or text via ObjectDBX with Lisp, without the alignment going awol if the objects justification is not left.  Once you change them, you have to open the drawing and do a regen, or move the block that the attributes are associated with before the alignment fixes itself.

You're right Tim, it's a nasty gotcha and I should have mentioned it. Thanks for the catch.

:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

mr_nick

  • Guest
Re: How do I get attributes nested within an xref?
« Reply #8 on: April 27, 2009, 06:43:50 AM »
I know this is an old topic I'm reviving but it deals exactly with an issue I'm currently having.

I have a piece of code which does much the same as the example in this post but since a recent change to my machine, the code has stopped working. I've been trawling around for examples of code which extract attribute data from blocks nested in xrefs and each one I've tried fails - basically because they all use the same basic principles.

The change to my machine that I made earlier reference to is simply the installation of Navisworks 2010. I am still running AutoCAD Architecture 2009 and up until the 2010 install everything was running sweetly.

The point of failure is the vla-get-objectname as this always gives an 'ActiveX Server returned an error: Element not found' error.

I have tried this on a few more machines and found that each machine with the 2009/2010 combination installed no longer handles the objectname cal but all those with just 2009 handle as cleanly as ever.

Is anybody able to think of a possible cause/solution to get this working again or possibly provide a non-VLisp, non-VBA solution to extract attribute data from a nested block?

T.Willey

  • Needs a day job
  • Posts: 5251
Re: How do I get attributes nested within an xref?
« Reply #9 on: April 27, 2009, 11:30:24 AM »
I know this is an old topic I'm reviving but it deals exactly with an issue I'm currently having.

I have a piece of code which does much the same as the example in this post but since a recent change to my machine, the code has stopped working. I've been trawling around for examples of code which extract attribute data from blocks nested in xrefs and each one I've tried fails - basically because they all use the same basic principles.

The change to my machine that I made earlier reference to is simply the installation of Navisworks 2010. I am still running AutoCAD Architecture 2009 and up until the 2010 install everything was running sweetly.

The point of failure is the vla-get-objectname as this always gives an 'ActiveX Server returned an error: Element not found' error.

I have tried this on a few more machines and found that each machine with the 2009/2010 combination installed no longer handles the objectname cal but all those with just 2009 handle as cleanly as ever.

Is anybody able to think of a possible cause/solution to get this working again or possibly provide a non-VLisp, non-VBA solution to extract attribute data from a nested block?

How are you wanting this to work?  Without ActiveX you will be limited to the current drawing, which may not be a problem for you.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

mr_nick

  • Guest
Re: How do I get attributes nested within an xref?
« Reply #10 on: April 27, 2009, 11:44:57 AM »
In my xref, there may or may not be a block present - if not then nothing need be done but if the block is present then I want to read a couple of attribute values - nothing more complex than that. Don't need to edit anything or manipulate the nested block in any way. The block and attributes will always have fixed names - it's always been a very simple process thus far but whatever Navisworks has done to my system, it no longer wants to play ball  :-(

If I use this code in a drawing containing an xref called 'MyXref' in a 2009 only machine

(setq BlkCol (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-Acad-Object))))
(setq BlkObj (vla-Item BlkCol "MyXref"))

I get the following output...
#<VLA-OBJECT IAcadBlock 000000003b3741f8>


Whereas if I use the same commands on the exact same drawing in AutoCAD 2009 but with Navisworks 2010 also installed I get this output...
#<VLA-OBJECT 195d9b64>



I even found some code attributed to yourself (see below) and gave that a whirl but it too failed with the error:
bad argument type: VLA-object collection: #<VLA-OBJECT 19565f84>

Code: [Select]
(setq BlkCol (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-Acad-Object))))
------------------
;; Get all nested blocks, make data lists
(setq bn (cdr (assoc 2 elist))); blockname
(if
(and
(setq Obj (vlax-ename->vla-object ent))
(= (vla-get-ObjectName Obj) "AcDbBlockReference")
); and
(progn
(get_nested_names obj BlkCol)
(MakeAttLists Obj)
(GetNestedBlocks (vla-get-Name Obj) BlkCol)
); progn
); if
------------------
;; Function to get 'nested' block attributes, uses 'recursive' technique
;;
(defun GetNestedBlocks ( BlkName BlkCol )
(vlax-for Obj (vla-Item BlkCol BlkName)
(if (= (vla-get-ObjectName Obj) "AcDbBlockReference")
(progn
(setq NBlock BlkName); Nested within..
(if (= (substr NBlock 1 1) "*")
(setq NBlock (strcase (vla-get-effectivename Obj)))
); if
(MakeAttLists Obj)
(GetNestedBlocks (vla-get-name Obj) BlkCol)
); progn
); if
); for
); function
------------------
;; Function to get 'nested' block names / handles of each into 'han_lst', appended to handles_lst
;;
(defun GetNestedBlockNames ( BlkName BlkCol )
(vlax-for Obj1 (vla-Item BlkCol BlkName)
(if (= (vla-get-ObjectName Obj1) "AcDbBlockReference")
(progn
(setq blname (vla-get-name Obj1))
(if (= (substr blname 1 1) "*")
(setq blname (strcase (vla-get-effectivename Obj1)))
); if
(setq han (vla-get-handle Obj1))
(setq han_lst (cons (list blname han) han_lst))
(setq add_lst (cons blname add_lst))
(GetNestedBlockNames (vla-get-name Obj1) BlkCol)
); progn
); if
); for
); function

T.Willey

  • Needs a day job
  • Posts: 5251
Re: How do I get attributes nested within an xref?
« Reply #11 on: April 27, 2009, 11:50:32 AM »
So from what I gather, you want it to search through all xrefs.  See if each one has a certain block, and if so, return the tag name and value from said block?
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

mr_nick

  • Guest
Re: How do I get attributes nested within an xref?
« Reply #12 on: April 27, 2009, 07:41:21 PM »
So from what I gather, you want it to search through all xrefs.  See if each one has a certain block, and if so, return the tag name and value from said block?

That's about the size of it.

T.Willey

  • Needs a day job
  • Posts: 5251
Re: How do I get attributes nested within an xref?
« Reply #13 on: April 27, 2009, 07:46:43 PM »
That isn't too hard then.  Don't have time to write the code now, but here is how it goes:

Search the block table ( tblnext )
Check to see if it's an xref ( dxf code 70 )
If it's an xref, then step through it ( entnext )
Check to see if the entity is an insert ( dxf code 0 ), and that it's the block you want ( dxf code 2 )
If so, step through it gathering the attribute's tag ( dxf code 2 ) and value ( dxf code 1 ), until you hit an entity name ' SEQEND ', which will be after all attributes.

Hope that helps.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

mr_nick

  • Guest
Re: How do I get attributes nested within an xref?
« Reply #14 on: April 27, 2009, 08:42:09 PM »
Sometimes, I never see the 'simple' approach. I always to tend to start at the opposite end of the scale and end up over-complicating things :ugly:

Thanks for bringing me back down to earth - it's helped me out of a big hole. Wouldn't mind knowing why it all went pear shaped though by installing Navisworks  :|

T.Willey

  • Needs a day job
  • Posts: 5251
Re: How do I get attributes nested within an xref?
« Reply #15 on: April 28, 2009, 10:55:58 AM »
Sometimes, I never see the 'simple' approach. I always to tend to start at the opposite end of the scale and end up over-complicating things :ugly:

Thanks for bringing me back down to earth - it's helped me out of a big hole. Wouldn't mind knowing why it all went pear shaped though by installing Navisworks  :|

You're welcome.  As far as Navisworks goes, I wouldn't know.  Maybe it messed with a dll that ActriveX uses.  I hope not.  Maybe someone with a better understanding of the hows of ActiveX could supply us with a more experienced suggestions for what happened.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.