This may be a little lengthy. Better grab a cup of joe before getting
started.

First off, an attribute is located inside a block entity.
This means the entities contained inside a block are called
sub-entities. All entities (Lines, text, attributes, etc.) inside the block are
sub-entities. You have to (I'll retract this later) start with the block entity and
step your way into it to find the sub-entities. Kind of like this :

You start with the Block's entity name and step through until you find SEQEND
using the ENTNEXT function. I'll get back to this a little later on.

You have a couple of choices on how to get to the attribute entity inside the
block. Now, after I've gone on the record saying "You have to start at the top
and step your way down through the sub-entities using ENTNEXT", I'm going to prove
myself wrong.

The easiest method is using NENTSEL. I have not discussed the NENTSEL
function until now. NENTSEL will return the DXF group code list for a sub-entity
inside a block or 3d Polyline. We will stick to blocks for this discussion.
You have to actually pick the attribute sub-entity and not any sub-entity
contained inside the block. You can then modify the DXF group codes and update the
attribute. This is fine for single selection and single manipulation of one
attribute inside the block. I'll give a quick demonstration of the NENTSEL function.

(setq ent(nentsel "\n Select a sub-entity: "))

NENTSEL returns the exact same thing as ENTSEL if the entity selected is not a
complex entity like a Block or 3d Polyline. If you selected acomplex entity such as
an attribute inside a block, NENTSEL would return something like this:

Let's take it apart, put it in order, and get rid of the codes that are not
needed:

Note: If you want to see the other group codes please see the Insert / Block entity
on this page.

(

(-1 . <Entity name: 40222278>) -1
- Entity name

(0 . "INSERT")
0 - Entity type

(2 . "Atl17")
2 - Name of the block

(10 5237.78 4923.46 0.0)
10 - Insertion Point

(41 . 20.0)
41 - X scale factor

(42 . 20.0)
42 - Y scale factor

(43 . 20.0)
43 - Z scale factor

(50 . 0.0)
50 - Rotation angle

(66 . 1)
66 - Attributes follow flag

)

Notice the red code. Code number 66. This is the important one for
finding attributes. If this code has a value of zero, there are no attributes in the
block. If it has a value of 1, the block contains attributes.
You find the attributes by stepping through the block using ENTNEXT until you reach the
SEQEND entity.

Note:
GROUP CODE 1 is optional.
It is present only if the block is an xref.

(2 . "HR")
2 - Name of Block

(5 . "EB6")
5 - Handle Name (If handles are turned on)

(8 . "TX")
8 - Layer Name

(10 1.5 0.5 0.0)
10 - Insertion Point

(41 . 1.0)
41 - X Scale Factor. Optional, 1 = default

(42 . 1.0)
42 - Y Scale Factor. Optional, 1 = default

(43 . 1.0)
43 - Z Scale Factor. Optional, 1 = default

(44 . 0.0)
44 - Don't worry about this. Optional.

(45 . 0.0)
45 - Don't worry about this. Optional.

(50 .5.96143)
50 - Rotation Angle Expressed in Radians

(66 . 0)
66 - Flag meaning attributes follow. Optional.

0 = Default
1 = Attributes-follow flag
A series of attribute entities is expected to follow the insert,
terminated by a SEQEND entity.

(67 . 0)
67 - Absent or zero indicates the entity is in
model space. If set to 1, paper space.

(70 . 0)
70 - Flag See the following:

Block
flags:
0 = Normal
1 = This is
an anonymous block generated by hatching,
associative dimensioning, other internal operations,
or an application
2 = This
block has attribute definitions
4 = This
block is an external reference (xref)
8 = This
block is an xref overlay
16 = This block is
externally dependent
32 = This is a resolved
external reference,
or dependent of an external reference
(ignored on input)
64 = This definition is
a referenced external reference
(ignored on input)

Note: Block flags may be combined. For instance,
a 70 DXF group code of 6 would mean the block
has attributes (code 2) and is an external
reference (code 4). Because 2 + 4 = 6

NOTE:The next series of codes are Vertex points (group 10
codes) followed by group 40 codes. These codes always appear in the list by order in which
they were created.

10 - Vertex 2D point
40 - Starting Width of the polyline. This is optional. Default = 0.
Code 40 is not used if group
code 43 is set.
41 - Ending Width of the polyline. This is optional. Default = 0.
Code 41 is not used if group
code 43 is set.
42 - Bulge factor. Used to create arcs in the polyline.
43 - Constant Width. Optional. Default = 0.
Code 43 is not used if codes
40 and 41 are set.

(foreach a enlist
;;;--- step through each sub-list (if(= 10 (car a))
;;;--- if the first item in the sub-list equals 10 then (setq myVertexList
;;;--- reset myVertexList to (append myVertexList
;;;--- the old vertex list (list
;;;--- plus a list containing (cdr a)
;;;--- the vertex point )
;;;--- close the list statement )
;;;--- close the append statement )
;;;--- close the setq statement )
;;;--- close the if statement)
;;;--- close the foreach statement

This would return:

( (1.0 1.0) (2.0 1.0) (2.0 2.0) (3.0 3.0) (1.0 4.0) )

A list of every vertex! Cool.

To get the layer name of the LWPolyline :

(cdr(assoc 8 enlist))

To see if the entity is indeed a LWPolyline entity :

(if (= "LWPOLYLINE" (cdr(assoc 0 enlist)))
(princ "\n It is a LWPolyLine")
(princ "\n It is not a LWPolyLine")
)

The group code 41 may contain zero or more items. The first group code 41 value is
the distance from the segment vertex along the miter vector to the point where the line
element's path intersects the miter vector. The next group code 41 value is the distance
along the line element's path from the point defined by the first group 41 to the actual
start of the line element. The next is the distance from the start of the line element to
the first break (or cut) in the line element. The successive group code 41 values continue
to list the start and stop points of the line element in this segment of the mline.
Linetypes do not affect group 41 lists.

The 2 group codes in mline entities and mlinestyle objects are redundant fields. These
groups should not be modified under any circumstances, although it is safe to read them
and use their values. The correct fields to modify are as follows:

Mline - The 340 group in the same object, which indicates the proper MLINESTYLE
object.

Mlinestyle -The 3 group value in the MLINESTYLE dictionary which precedes the 350 group
that has the handle or entity name of the current mlinestyle.

Here's an example of how to get all of the vertices in a list:

(setq en(car(entsel "\n Select a MLine: "))) ;;;---
Get the entity name

(setq v1(cdr(assoc 10 enlist)))
;;;--- Get the starting point of the mline

(setq myVertexList(append myVertexList (list v1))) ;;;---
Add the point to the list

(foreach a enlist
;;;--- step through each sub-list (if(= 11 (car a))
;;;--- if the first item in the sub-list equals 11 then (setq myVertexList
;;;--- reset myVertexList to (append myVertexList
;;;--- the old vertex list (list
;;;--- plus a list containing (cdr a)
;;;--- the vertex point )
;;;--- close the list statement )
;;;--- close the append statement )
;;;--- close the setq statement )
;;;--- close the if statement)
;;;--- close the foreach statement

Note: Use curly braces ({ }) to apply a format change only to the text within the braces.
You can nest braces up to eight levels deep.

NOTE 2 :String
Length!

If the number of characters in an MText entity is
less than 250, all characters will be in group code number 1. If you exceed 249
characters, the characters are broken up in 250 character chunks and placed under group
code number 3. The remainder of the characters will be in group code 1. For
instance, if I change the MText entity we used in the example above:

(1 . "This is an Mtext string. ")

into a string that is 600 characters long, the MText
value would look something like this:

Notice there are no vertices shown. You have to step through
this entity looking at the sub-entities for the vertices until you come across the SEQEND
entity. Sound familar? It should. This is exactly like the Attribute
Entity. Pretty much anyway. Please read the Attribute
section above for instructions on the ENTNEXT function used to step into an entity looking
for sub-entities and the SEQEND entity definition. When you get through, come back
to here.

So, we now know how to step into an entity. Let's do that for
this polyline and save a list of all of the vertices.

(defun C:PTEST()

;;;--- Get the entity's name
(setq en(car(entsel "\n Select a PolyLine: ")))

;;;--- Get the DXF group codes of the entity
(setq enlist(entget en))

;;;--- Create an empty list to hold the points
(setq ptList(list))

;;;--- Get the sub-entities name
(setq en2(entnext en))

;;;--- Get the dxf group codes of the sub-entity
(setq enlist2(entget en2))

;;;--- While the polyline has a next vertice
(while (not (equal (cdr(assoc 0 (entget(entnext en2))))"SEQEND"))

;;;--- Get the next sub-entity
(setq en2(entnext en2))

;;;--- Get its dxf group codes
(setq enlist2(entget en2))

;;;--- Check to make sure it is not a spline reference point
(if(/= 16 (cdr(assoc 70 enlist2)))

;;;--- It is a vertex, save the point in a list
[ptlist]
(setq ptList(append ptList (list (cdr(assoc 10
enlist2)))))

)
)

(princ)
)

If you run this program and then type this in the command line: Command: ptList!<enter>

It will return a list of all of the vertices and will look
something like this: