The last post got me thinking about how to get the names of all the colours that are contained in a particular color-book inside AutoCAD (the last post also contains the explanation for my using both "color" and "colour" in the same sentence, in case that bothers anyone :-).
Color-books are stored in .acb files: these files are essentially XML files with the RGB values encoded to prevent people from editing them and polluting the colour definitions on a particular system. So while the RGB information is not directly useful, it is very possible to iterate through these files and extract the names of the colours contained in a particular color-book.
This was also an excuse for me to look at the XmlReader class, to see how I might use that. It turns out that you can't instanciate an XmlReader directly - it's an abstract class. You need to use one of its concrete children, such as XmlTextReader or XmlNodeReader. XmlNodeReader gives you tree-like access to the XML content (such as you get when using the DOM to read an XML file), while the XmlTextReader is a forward-only reader which allows you to (for all intents and purposes) stream in XML content such as you might when using SAX. To understand how XmlTextReader differs from SAX, see this brief comparison.
I have historically used DOM to read XML files that need to maintained in their entirety (as they have internal references, etc.) and SAX when this was less of a concern (such as when iterating through to harvest certain data). SAX was always quicker, but you had to maintain more state information if the content was inter-related.
In this case I would therefore have chosen SAX over DOM, so in the .NET world this means XmlTextReader is the class to use.
One other quick comment on the implementation: the code uses HostApplicationServices.FindFile() to find the location of the particular .acb file we’re interested in (typically inside “Support/Color” beneath the AutoCAD install folder).
Here's the C# code:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using System;
using System.Xml;
namespace ColorBookApplication
{
public class Commands
{
[CommandMethod("LC")]
static public void ListRalColors()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
string loc =
HostApplicationServices.Current.FindFile(
"ral classic.acb",
db,
FindFileHint.Default
);
XmlTextReader xr =
new XmlTextReader(loc);
while (xr.Read())
{
xr.MoveToContent();
if (xr.NodeType == XmlNodeType.Element &&
xr.LocalName == "colorName")
{
if (xr.Read())
{
if (xr.HasValue)
{
ed.WriteMessage("\n" + xr.Value);
}
}
}
}
xr.Close();
}
}
}
And here's what happens when we run the LC command:
Command: lc
RAL 1000
RAL 1001
RAL 1002
... entries deleted...
RAL 9016
RAL 9017
RAL 9018