AutoLISP: The Complete Guide — Chapter 14 / 16

Extended Data and Dictionaries

So far, we have created, modified, and read entities with their standard geometric properties: points, radii, layers, colors. But in a real program, you will often need to attach your own information to an entity — a part number, a supplier reference, a link to another entity. AutoLISP offers several mechanisms for this, from the simplest to the most powerful.

Extended Data (xdata)

Extended data (xdata) allows you to attach custom information to any entity in the drawing. This data is invisible to the user — it does not display on screen — but your program can read and modify it.

Registering an Application

Before attaching xdata, you must register an application name with regapp. This name serves as an identifier to group your data:

(regapp "WIIP_PIPING")

regapp returns the application name if registration succeeds, or nil if the name is already registered (which is not an error). In practice, you call regapp at the beginning of your program without worrying about the return value.

Convention: choose a unique application name that clearly identifies your program. A prefix with your company name helps avoid collisions with other developers.

Attaching xdata to an Entity

Xdata is added to the -3 group of an entity's DXF list. Each piece of data has a specific DXF code:

Code Data Type Example
1000 String (1000 . "DN100")
1001 Application name (start of an xdata group) (1001 . "WIIP_PIPING")
1005 Handle reference (link to another entity) (1005 . "1A3F")
1010 3D point (1010 0.0 0.0 0.0)
1040 Real number (1040 . 114.3)
1070 16-bit integer, from -32,768 to 32,767 — typical for color indices and flags (1070 . 42)
1071 32-bit long integer, from -2,147,483,648 to 2,147,483,647 — for large values (1071 . 100000)

Here is how to attach xdata to the last entity created:

;; Register the application
(regapp "WIIP_PIPING")

;; Get the last entity
(setq entity (entlast))
(setq data (entget entity))

;; Add the xdata
(setq data
  (append data
    (list
      (list -3
        (list "WIIP_PIPING"
          (cons 1000 "DN100")           ; Nominal diameter
          (cons 1040 114.3)             ; Outside diameter in mm
          (cons 1070 10)                ; Nominal pressure (PN)
        )
      )
    )
  )
)

;; Apply the modification
(entmod data)

The -3 code tells AutoCAD that what follows is a block of extended data. Inside, the data is grouped by application name.

Reading xdata from an Entity

By default, entget does not return xdata. You must explicitly request the data for a given application:

;; Read the entity WITH its xdata
(setq data (entget (entlast) '("WIIP_PIPING")))

;; Extract the xdata group
(setq xdata (assoc -3 data))

The result of (assoc -3 data) looks like:

(-3 ("WIIP_PIPING"
      (1000 . "DN100")
      (1040 . 114.3)
      (1070 . 10)
    )
)

To extract a specific value:

;; Get the application data
(setq app-data (cdadr (assoc -3 data)))

;; Find the nominal diameter
(cdr (assoc 1000 app-data))  ; → "DN100"

;; Find the outside diameter
(cdr (assoc 1040 app-data))  ; → 114.3

Complete Example: Labeling Entities

This program attaches a unique identifier to each selected entity, then allows you to retrieve it:

(defun c:label (/ selection-set index entity data identifier)
  (regapp "WIIP_ID")
  (setq selection-set (ssget))

  (if selection-set
    (progn
      (setq index 0)
      (repeat (sslength selection-set)
        (setq entity (ssname selection-set index))
        (setq identifier (strcat "ID-" (itoa (1+ index))))

        ;; Read the entity
        (setq data (entget entity))

        ;; Add the xdata
        (setq data
          (append data
            (list
              (list -3
                (list "WIIP_ID"
                  (cons 1000 identifier)
                )
              )
            )
          )
        )

        (entmod data)
        (setq index (1+ index))
      )

      (princ (strcat "\n" (itoa (sslength selection-set)) " entity(ies) labeled."))
    )
    (princ "\nNo selection.")
  )
  (princ)
)

(defun c:read-label (/ selection entity data xdata)
  (setq selection (entsel "\nSelect an entity: "))
  (if selection
    (progn
      (setq entity (car selection))
      (setq data (entget entity '("WIIP_ID")))
      (setq xdata (assoc -3 data))

      (if xdata
        (princ (strcat "\nIdentifier: " (cdr (assoc 1000 (cdadr xdata)))))
        (princ "\nThis entity has no identifier.")
      )
    )
    (princ "\nNo selection.")
  )
  (princ)
)

Extension Dictionaries

Xdata is perfect for attaching data to a specific entity. But what if you want to store information at the drawing level itself — for example, your program's configuration, a global counter, or a lookup table? That is the role of extension dictionaries.

The Named Object Dictionary

Every AutoCAD drawing contains a Named Object Dictionary (NOD). It is the root of the dictionary tree. You access it with the namedobjdict function:

(setq root-dictionary (namedobjdict))

This function returns the entity name of the root dictionary. You can then search in it or add entries to it.

Searching a Dictionary

The dictsearch function looks up an entry in a dictionary by name:

;; Search for a dictionary named "WIIP_CONFIG"
(setq result (dictsearch (namedobjdict) "WIIP_CONFIG"))

If the entry exists, dictsearch returns its DXF list. Otherwise, it returns nil.

Storing Data with Xrecords

An xrecord is a database object that can hold arbitrary data. It is the equivalent of a record in a database. You create it with entmakex (a variant of entmake that returns the entity name):

;; Create an xrecord
(setq xrecord
  (entmakex
    (list
      '(0 . "XRECORD")
      '(100 . "AcDbXrecord")
      (cons 1 "Industrial piping")        ; String
      (cons 70 42)                         ; Integer
      (cons 40 3.14)                       ; Real
    )
  )
)

Standard DXF codes are used to type the data in an xrecord:

Code Type
1 String
10 3D point
40 Real number
70 Integer
300-309 Additional strings

Adding an Xrecord to the Dictionary

Once the xrecord is created, you attach it to the named object dictionary with dictadd:

(dictadd (namedobjdict) "WIIP_CONFIG" xrecord)

Complete Example: Persistent Configuration

This program stores and reads a configuration in the drawing:

(defun save-configuration (project-name scale / xrecord existing)
  ;; Check if the configuration already exists
  (setq existing (dictsearch (namedobjdict) "WIIP_CONFIG"))

  (if existing
    ;; Remove the old xrecord
    (dictremove (namedobjdict) "WIIP_CONFIG")
  )

  ;; Create a new xrecord
  (setq xrecord
    (entmakex
      (list
        '(0 . "XRECORD")
        '(100 . "AcDbXrecord")
        (cons 1 project-name)
        (cons 40 scale)
      )
    )
  )

  ;; Add it to the dictionary
  (dictadd (namedobjdict) "WIIP_CONFIG" xrecord)
  (princ (strcat "\nConfiguration saved for " project-name))
  (princ)
)

(defun read-configuration (/ result)
  (setq result (dictsearch (namedobjdict) "WIIP_CONFIG"))

  (if result
    (progn
      (princ (strcat "\nProject: " (cdr (assoc 1 result))))
      (princ (strcat "\nScale: " (rtos (cdr (assoc 40 result)) 2 2)))
    )
    (princ "\nNo configuration found.")
  )
  (princ)
)

;; Usage
(defun c:save-config (/ name scale)
  (setq name (getstring T "\nProject name: "))
  (setq scale (getreal "\nScale: "))
  (save-configuration name scale)
)

(defun c:read-config ()
  (read-configuration)
)

The decisive advantage of dictionaries is that the data is persistent: it is saved with the DWG file and survives across AutoCAD sessions.

Xdata or Dictionary: How to Choose?

Criterion Xdata Extension Dictionary
Scope Attached to an entity At the drawing level
Maximum size 16 KB per application per entity No practical limit
Complexity Simple More complex
Use case Custom properties of an entity Global configuration, data tables

As a general rule: if the data is tied to a specific entity, use xdata. If it concerns the drawing as a whole, use a dictionary.

Linking Entities Together Through Handles

Every entity in the drawing has a handle — a unique identifier in the form of a hexadecimal string. You find it in DXF code 5:

(setq data (entget (entlast)))
(cdr (assoc 5 data))  ; → "1A3F" (for example)

This handle remains stable: it does not change when you save and reopen the drawing. This is what makes it ideal for creating links between entities.

Imagine you want to link an annotation text to the line it describes. The idea is to store the line's handle in the text's xdata:

(defun c:link-annotation (/ line-selection line line-data line-handle
                            text-selection text text-data)
  (regapp "WIIP_LINK")

  ;; Select the line
  (setq line-selection (entsel "\nSelect the line: "))
  (if (null line-selection)
    (progn (princ "\nNo selection.") (princ) (exit))
  )
  (setq line (car line-selection))
  (setq line-data (entget line))
  (setq line-handle (cdr (assoc 5 line-data)))

  ;; Select the text
  (setq text-selection (entsel "\nSelect the text: "))
  (if (null text-selection)
    (progn (princ "\nNo selection.") (princ) (exit))
  )
  (setq text (car text-selection))
  (setq text-data (entget text))

  ;; Attach the line's handle to the text via xdata
  (setq text-data
    (append text-data
      (list
        (list -3
          (list "WIIP_LINK"
            (cons 1005 line-handle)    ; Code 1005 = handle reference
          )
        )
      )
    )
  )
  (entmod text-data)

  (princ (strcat "\nLink created to handle " line-handle))
  (princ)
)

The xdata code 1005 is specifically designed to store handle references. This is not trivial — AutoCAD treats it differently from a plain string (code 1000).

Finding the Linked Entity

To find an entity from its handle, use handent:

(defun c:follow-link (/ selection entity data xdata target-handle target)
  (setq selection (entsel "\nSelect the annotation: "))
  (if (null selection)
    (progn (princ "\nNo selection.") (princ) (exit))
  )

  (setq entity (car selection))
  (setq data (entget entity '("WIIP_LINK")))
  (setq xdata (assoc -3 data))

  (if xdata
    (progn
      (setq target-handle (cdr (assoc 1005 (cdadr xdata))))
      (setq target (handent target-handle))

      (if target
        (progn
          (princ (strcat "\nLinked entity found: " target-handle))
          ;; Highlight the target entity
          (redraw target 3)
        )
        (princ "\nThe linked entity no longer exists in the drawing.")
      )
    )
    (princ "\nThis entity has no link.")
  )
  (princ)
)

WBLOCK and Handle Translation

This is a crucial point to understand. When you use WBLOCK (write a block to an external file), AutoCAD translates the handles: entities receive new handles in the destination file. And thanks to code 1005, AutoCAD knows that the stored value is a handle and automatically updates the reference. This is why you should not use code 1000 (ordinary string) to store a handle — AutoCAD would not know that it needs to translate it.

However, during an internal copy (for example with _COPY or (command "_COPY" ...)), there is no handle translation. The copy retains the same xdata values as the original, including handle references. Both entities will therefore point to the same target. This is a behavior to keep in mind: after a copy, you may need to update the links manually.

Operation Handle translation (code 1005)
WBLOCK (export to external file) Yes — references are updated
INSERT (import from external file) Yes — references are updated
Internal COPY (_COPY) No — references remain identical
COPYCLIP / PASTECLIP Yes — similar treatment to WBLOCK/INSERT

Summary

Concept Function Description
Register an application regapp Declares an application name for xdata
Read xdata (entget ename '("APP")) Retrieves the extended data of an entity
Root dictionary (namedobjdict) Accesses the named object dictionary
Search a dictionary (dictsearch dict "name") Looks up an entry by name
Add to dictionary (dictadd dict "name" xrec) Attaches an xrecord to the dictionary
Entity handle (cdr (assoc 5 data)) Unique and stable identifier
Entity from handle (handent "1A3F") Finds an entity by its handle

In the next chapter, we will see how to automatically react to drawing modifications using reactors.


Helping hand Need an AutoCAD (AutoLISP, ObjectARX, .NET, VBA) development? Contact me for a free quote.