I received a PM from a kindly member of our swamp collective; an inquiry that went something like this --
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) --
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 --(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
)
(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
)
(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)
)
)
)
)
[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 --
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.