I have constructed a function to accomplish the second described task.
Since I have voluntarily donated my time to help you understand, please take the time to carefully read the comments.
([color=BLUE]defun[/color] c:AutomaticallyCopyAttributes ( [color=BLUE]/[/color] SourceBlock DestBlock ss1 ss2 block elist alist i value )
[color=GREEN];; Define function and localise variables.[/color]
[color=GREEN];; The variable localisation is *especially* important in this case[/color]
[color=GREEN];; since we are using a self-referencing variable ('alist') later on to[/color]
[color=GREEN];; create our association list of attribute data.[/color]
[color=GREEN];; To understand why this is so important, read my tutorial at:[/color]
[color=GREEN];; [/color]
[color=GREEN];; www.lee-mac.com/localising.html[/color]
[color=GREEN];; [/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; Example courtesy of Lee Mac 2011 - www.lee-mac.com ;;[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; Program Description: ;;[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; This program will first retrieve a SelectionSet of all attributed[/color]
[color=GREEN];; blocks with the name as held by the 'SourceBlock' variable.[/color]
[color=GREEN];; An association list of ((<tag> . <value>) ... ) will then be[/color]
[color=GREEN];; constructed using the attribute data of the first block in this[/color]
[color=GREEN];; SelectionSet.[/color]
[color=GREEN];; A SelectionSet of all attributed blocks with the name held by the[/color]
[color=GREEN];; 'DestBlock' will then be retrieved. The program will proceed to[/color]
[color=GREEN];; iterate through this SelectionSet and, for each attribute in each[/color]
[color=GREEN];; block: if the attribute tag string is present in the association[/color]
[color=GREEN];; list as collected from the source block, the value of such attribute[/color]
[color=GREEN];; will be updated to display the value held by the respective attribute[/color]
[color=GREEN];; in the source block - effectively copying all attributes.[/color]
[color=GREEN];; [ Annotation follows each expression ][/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; Main Function ;;[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
([color=BLUE]setq[/color] SourceBlock [color=MAROON]"blockA"[/color])
[color=GREEN];; Source Block from which attribute data will be sourced.[/color]
([color=BLUE]setq[/color] DestBlock [color=MAROON]"blockB"[/color])
[color=GREEN];; Destination Blocks to which the attribute data will be copied.[/color]
([color=BLUE]if[/color]
[color=GREEN];; IF requires two arguments and may take an optional third:[/color]
[color=GREEN];;[/color]
[color=GREEN];; (IF <test expr>[/color]
[color=GREEN];; <then expr>[/color]
[color=GREEN];; [else expr][/color]
[color=GREEN];; )[/color]
[color=GREEN];; IF the test expression returns a non-nil value (does not have to be[/color]
[color=GREEN];; explicitely T, just anything non-nil; the THEN expression will be[/color]
[color=GREEN];; evaluated. Otherwise, the ELSE expression will be evaluated if supplied;[/color]
[color=GREEN];; if not supplied, the IF function will return nil.[/color]
([color=BLUE]and[/color]
[color=GREEN];; Using the AND operator means ALL of the expressions passed to it must[/color]
[color=GREEN];; return a non-nil value for the AND function to return T.[/color]
([color=BLUE]setq[/color] ss1 ([color=BLUE]ssget[/color] [color=MAROON]"_X"[/color] ([color=BLUE]list[/color] ([color=BLUE]cons[/color] 0 [color=MAROON]"INSERT"[/color]) ([color=BLUE]cons[/color] 2 SourceBlock) ([color=BLUE]cons[/color] 66 1))))
([color=BLUE]setq[/color] ss2 ([color=BLUE]ssget[/color] [color=MAROON]"_X"[/color] ([color=BLUE]list[/color] ([color=BLUE]cons[/color] 0 [color=MAROON]"INSERT"[/color]) ([color=BLUE]cons[/color] 2 DestBlock) ([color=BLUE]cons[/color] 66 1))))
) [color=GREEN];; End AND[/color]
[color=GREEN];; IF we can retrieve a SelectionSet of all attributed blocks, [(66 . 1) is used[/color]
[color=GREEN];; to ensure we retrieve only *attributed* blocks], with name equal to that[/color]
[color=GREEN];; held by the 'SourceBlock' variable [Note that this will *not* include[/color]
[color=GREEN];; Dynamic blocks as these may take an anonymous block name], AND a SelectionSet[/color]
[color=GREEN];; of all attributed blocks with name equal to that held by the 'DestBlock' variable[/color]
[color=GREEN];; then do the following:[/color]
([color=BLUE]progn[/color]
[color=GREEN];; Use the progn function to wrap the following statements into a single[/color]
[color=GREEN];; expression that we can pass to the IF function to constitute the 'Then' argument.[/color]
([color=BLUE]setq[/color] block ([color=BLUE]ssname[/color] ss1 0))
[color=GREEN];; Retrieve the first entity in the SelectionSet (SelectionSets have a zero-based index).[/color]
([color=BLUE]while[/color] ([color=BLUE]eq[/color] [color=MAROON]"ATTRIB"[/color] ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 0 ([color=BLUE]entget[/color] ([color=BLUE]setq[/color] block ([color=BLUE]entnext[/color] block))))))
[color=GREEN];; While we are dealing with ATTRIBute entities, do the following.[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; Note that we use entnext to view the ATTRIBute entities of the attributed[/color]
[color=GREEN];; block. The entnext function takes an entity argument and merely returns the[/color]
[color=GREEN];; entity that follows the supplied entity in the drawing database. When[/color]
[color=GREEN];; entities are created in a drawing, they are added to this drawing database[/color]
[color=GREEN];; in the order that they were created.[/color]
[color=GREEN];; When an attributed block is created in the drawing, the INSERT entity is[/color]
[color=GREEN];; created, then a number of ATTRIBute entities are created, and a terminating[/color]
[color=GREEN];; SEQEND entity is finally created to signal the end of the block information.[/color]
[color=GREEN];; Hence when we supply our INSERT entity (variable 'block') to the entnext[/color]
[color=GREEN];; function, the function returns the next entity in the database following this[/color]
[color=GREEN];; entity, which is our ATTRIBute entities. Notice that after we return the[/color]
[color=GREEN];; ATTRIB entity using the entnext function, we bound it to the 'block' variable -[/color]
[color=GREEN];; this ensures that, on the next evaluation of the WHILE test expression, the[/color]
[color=GREEN];; entnext function is fed the previous ATTRIBute entity and so returns the entity[/color]
[color=GREEN];; following this, whether it be another ATTRIBute or the SEQEND entity.[/color]
[color=GREEN];; Notice that the WHILE test expression could also be phrased:[/color]
[color=GREEN];;[/color]
[color=GREEN];; (while (not (eq "SEQEND" (cdr (assoc 0 (entget (setq block (entnext block)))))))[/color]
[color=GREEN];;[/color]
[color=GREEN];; to test for the appearance of the terminating SEQEND entity.[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
([color=BLUE]setq[/color] elist ([color=BLUE]entget[/color] block))
[color=GREEN];; Get the DXF data of the attribute entity.[/color]
([color=BLUE]setq[/color] alist ([color=BLUE]cons[/color] ([color=BLUE]cons[/color] ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 2 elist)) ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 1 elist))) alist))
[color=GREEN];; If the cons function is supplied with two atoms, it will create a dotted pair.[/color]
[color=GREEN];; Using this knowledge, we create a dotted pair using the Attribute Tag (DXF 2) and[/color]
[color=GREEN];; the Attribute Value (DXF 1) of the ATTRIBute entity:[/color]
[color=GREEN];; ("TAG1" . "VALUE1")[/color]
[color=GREEN];; If the cons function is supplied with an atom and a list, it will add the atom[/color]
[color=GREEN];; to the beginning of the list. In this way we create our association list:[/color]
[color=GREEN];; alist = (("TAG1" . "VALUE1") ("TAG2" . "VALUE2") ... ("TAGN" . "VALUEN"))[/color]
) [color=GREEN];; End WHILE[/color]
[color=GREEN];; Now that we have our association list containing the attribute data, we can[/color]
[color=GREEN];; proceed to iterate through the SelectionSet containing the destination attributed[/color]
[color=GREEN];; blocks.[/color]
([color=BLUE]repeat[/color] ([color=BLUE]setq[/color] i ([color=BLUE]sslength[/color] ss2))
[color=GREEN];; Repeat the following set of expressions a number of times equal to the number[/color]
[color=GREEN];; of objects in the SelectionSet 'ss2'.[/color]
[color=GREEN];; At the same time we can initialise our counter variable 'i' since the integer[/color]
[color=GREEN];; argument supplied to the repeat function is only evaluated once.[/color]
([color=BLUE]setq[/color] block ([color=BLUE]ssname[/color] ss2 ([color=BLUE]setq[/color] i ([color=BLUE]1-[/color] i))))
[color=GREEN];; Retrieve the entity at index 'i' in the SelectionSet. We may as well use the[/color]
[color=GREEN];; same variable since it still points to data of ename type (note that it wouldn't[/color]
[color=GREEN];; matter if it didn't, as is the versatility offered by a high-level language such[/color]
[color=GREEN];; as LISP).[/color]
([color=BLUE]while[/color] ([color=BLUE]eq[/color] [color=MAROON]"ATTRIB"[/color] ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 0 ([color=BLUE]entget[/color] ([color=BLUE]setq[/color] block ([color=BLUE]entnext[/color] block))))))
[color=GREEN];; Using exactly the same logic as above, we can iterate through the[/color]
[color=GREEN];; attributes of each block in the SelectionSet of 'destination' blocks.[/color]
([color=BLUE]setq[/color] elist ([color=BLUE]entget[/color] block))
[color=GREEN];; Same as above, retrieving the DXF Data of the ATTRIBute entity. Re-using[/color]
[color=GREEN];; the same variable name for clarity and ease of localisation...[/color]
([color=BLUE]if[/color] ([color=BLUE]setq[/color] value ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 2 elist)) alist)))
[color=GREEN];; Attempt to locate an entry in our association data list with the[/color]
[color=GREEN];; first item equal to the tag of the ATTRIBute entity. If found, bound[/color]
[color=GREEN];; the second element in this entry (the value) to the variable 'value'.[/color]
([color=BLUE]entupd[/color] ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] -1 ([color=BLUE]entmod[/color] ([color=BLUE]subst[/color] ([color=BLUE]cons[/color] 1 value) ([color=BLUE]assoc[/color] 1 elist) elist)))))
[color=GREEN];; Use the 'subst' function to SUBSTitute the pair (1 . <value>) for the existing[/color]
[color=GREEN];; pair in the DXF Data of the ATTRIBute entity.[/color]
[color=GREEN];; When substituted, the new DXF Data list is returned by the subst function.[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; Note that the subst function does *NOT* make any modification to the entity.[/color]
[color=GREEN];; The subst function will perform the substitution on the supplied list[/color]
[color=GREEN];; and return the new list.[/color]
[color=GREEN];; I suppose the point I am trying to make is that the DXF Data list of the entity[/color]
[color=GREEN];; is just like any other list, and in this way it can be manipulated[/color]
[color=GREEN];; like any other list.[/color]
[color=GREEN];; Similarly, the subst function can operate on any list, and is not[/color]
[color=GREEN];; only restricted to operating on DXF data returned by the entget function.[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; Following the substitution of the new value under DXF group 1,[/color]
[color=GREEN];; the DXF Data list is fed to the entmod function, which changes the entry[/color]
[color=GREEN];; in the drawing database to reflect the modification.[/color]
[color=GREEN];; Finally, the entupd function updates the entity on screen to display[/color]
[color=GREEN];; the updated information in the drawing database.[/color]
[color=GREEN];; DXF code -1 always points to the entity name for which the DXF data[/color]
[color=GREEN];; is referencing, so its an easy way to ensure we are entupd'ing the[/color]
[color=GREEN];; correct entity without worrying about variables.[/color]
) [color=GREEN];; End IF[/color]
) [color=GREEN];; End WHILE[/color]
) [color=GREEN];; End REPEAT[/color]
) [color=GREEN];; End PROGN[/color]
[color=GREEN];; So, we've supplied THEN argument for the IF function, all wrapped up into[/color]
[color=GREEN];; one expression by the progn function.[/color]
[color=GREEN];; Now, if necessary, we can supply an ELSE argument (optional), to be evaluated[/color]
[color=GREEN];; should the test expression return nil, hence indicating that the program[/color]
[color=GREEN];; failed to retrieve both SelectionSets.[/color]
([color=BLUE]princ[/color] [color=MAROON]"\n** Blocks not Found **"[/color])
[color=GREEN];; A simple message printed to inform the user of such a case.[/color]
) [color=GREEN];; End IF[/color]
([color=BLUE]princ[/color])
[color=GREEN];; Finally, exit cleanly - suppressing the return of the last evaluated expression.[/color]
) [color=GREEN];; End DEFUN[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
[color=GREEN];; End of Function ;;[/color]
[color=GREEN];; ---------------------------------------------------------------------;;[/color]
If you have any questions about the code, or the comments, please ask.