Extracting XML data from drawings using a new .NET API in AutoCAD 2009
This post is the latest in the series of closer looks at the new APIs in AutoCAD 2009. It covers the Data Extraction API, a new .NET API allowing you to drive the Data Extraction feature inside AutoCAD.
There is a very thorough C# sample included on the ObjectARX SDK (under samples/dotNet/DataExtraction), so I thought I'd focus on a much simpler example where we extract data from a single drawing.
Here's the C# code:
using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DataExtraction;
namespace DataExtraction
{
public class Commands
{
const string path =
@"c:\Program Files\Autodesk\AutoCAD 2009\Sample\";
const string fileName =
"Visualization - Aerial.dwg";
const string outputXmlFile =
@"c:\temp\data-extract.xml";
[CommandMethod("extd")]
public void extractData()
{
if (!System.IO.File.Exists(path + fileName))
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed =
doc.Editor;
ed.WriteMessage("\nFile does not exist.");
return;
}
// Create some settings for the extraction
IDxExtractionSettings es =
new DxExtractionSettings();
IDxDrawingDataExtractor de =
es.DrawingDataExtractor;
de.Settings.ExtractFlags =
ExtractFlags.ModelSpaceOnly |
ExtractFlags.XrefDependent |
ExtractFlags.Nested;
// Add a single file to the settings
IDxFileReference fr =
new DxFileReference(path, path + fileName);
de.Settings.DrawingList.AddFile(fr);
// Scan the drawing for object types & their properties
de.DiscoverTypesAndProperties(path);
List<IDxTypeDescriptor> types =
de.DiscoveredTypesAndProperties;
// Select all the types and properties for extraction
// by adding them one-by-one to these two lists
List<string> selTypes = new List<string>();
List<string> selProps = new List<string>();
foreach (IDxTypeDescriptor type in types)
{
selTypes.Add(type.GlobalName);
foreach (
IDxPropertyDescriptor pr in type.Properties
)
{
if (!selProps.Contains(pr.GlobalName))
selProps.Add(pr.GlobalName);
}
}
// Pass this information to the extractor
de.Settings.SetSelectedTypesAndProperties(
types,
selTypes,
selProps
);
// Now perform the extraction itself
de.ExtractData(path);
// Get the results of the extraction
System.Data.DataTable dataTable =
de.ExtractedData;
// Output the extracted data to an XML file
if (dataTable.Rows.Count > 0)
{
dataTable.TableName = "My_Data_Extract";
dataTable.WriteXml(outputXmlFile);
}
}
}
}
Here are the first few objects from the output file found in c:\temp\data-extract.xml after running the EXTD command:
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<My_Data_Extract>
<AcDxHandleData>183</AcDxHandleData>
<Layer>0</Layer>
<LinetypeScale>1</LinetypeScale>
<PlotStyleName>ByLayer</PlotStyleName>
<LineWeight>ByLayer</LineWeight>
<Material>Material 3</Material>
<Linetype>ByLayer</Linetype>
<Color>ByLayer</Color>
<AcDxObjectTypeName>3D Solid</AcDxObjectTypeName>
<AcDxObjectTypeGlobalName>
Autodesk.AutoCAD.DatabaseServices.Solid3d
</AcDxObjectTypeGlobalName>
<AcDxDwgSummaryDwgName>
Visualization - Aerial.dwg
</AcDxDwgSummaryDwgName>
<AcDxDwgSummaryDwgLocation>
c:\Program Files\Autodesk\AutoCAD 2009\Sample
</AcDxDwgSummaryDwgLocation>
<AcDxDwgSummaryDwgSize>472480</AcDxDwgSummaryDwgSize>
<AcDxDwgSummaryDwgCreated>
2007-01-03T00:44:20+01:00
</AcDxDwgSummaryDwgCreated>
<AcDxDwgSummaryDwgModified>
2007-01-03T00:44:20+01:00
</AcDxDwgSummaryDwgModified>
<AcDxDwgSummaryDwgAccessed>
2008-03-03T11:40:53.796875+01:00
</AcDxDwgSummaryDwgAccessed>
<AcDxDwgSummaryDwgTitle />
<AcDxDwgSummaryDwgSubject />
<AcDxDwgSummaryDwgAuthor />
<AcDxDwgSummaryDwgKeywords />
<AcDxDwgSummaryDwgComments />
<AcDxDwgSummaryDwgHyperLinkBase />
<AcDxDwgSummaryDwgLastSavedBy>
thompsl
</AcDxDwgSummaryDwgLastSavedBy>
<AcDxDwgSummaryDwgRevisionNumber />
<AcDxDwgSummaryDwgTotalEditingTime>
1179
</AcDxDwgSummaryDwgTotalEditingTime>
<AcDxEntityHyperlink />
</My_Data_Extract>
<My_Data_Extract>
<AcDxHandleData>191</AcDxHandleData>
<Layer>0</Layer>
<LinetypeScale>1</LinetypeScale>
<PlotStyleName>ByLayer</PlotStyleName>
<LineWeight>ByLayer</LineWeight>
<Material>Material 3</Material>
<Linetype>ByLayer</Linetype>
<Color>ByLayer</Color>
<AcDxObjectTypeName>3D Solid</AcDxObjectTypeName>
<AcDxObjectTypeGlobalName>
Autodesk.AutoCAD.DatabaseServices.Solid3d
</AcDxObjectTypeGlobalName>
<AcDxDwgSummaryDwgName>
Visualization - Aerial.dwg
</AcDxDwgSummaryDwgName>
<AcDxDwgSummaryDwgLocation>
c:\Program Files\Autodesk\AutoCAD 2009\Sample
</AcDxDwgSummaryDwgLocation>
<AcDxDwgSummaryDwgSize>472480</AcDxDwgSummaryDwgSize>
<AcDxDwgSummaryDwgCreated>
2007-01-03T00:44:20+01:00
</AcDxDwgSummaryDwgCreated>
<AcDxDwgSummaryDwgModified>
2007-01-03T00:44:20+01:00
</AcDxDwgSummaryDwgModified>
<AcDxDwgSummaryDwgAccessed>
2008-03-03T11:40:53.796875+01:00
</AcDxDwgSummaryDwgAccessed>
<AcDxDwgSummaryDwgTitle />
<AcDxDwgSummaryDwgSubject />
<AcDxDwgSummaryDwgAuthor />
<AcDxDwgSummaryDwgKeywords />
<AcDxDwgSummaryDwgComments />
<AcDxDwgSummaryDwgHyperLinkBase />
<AcDxDwgSummaryDwgLastSavedBy>
thompsl
</AcDxDwgSummaryDwgLastSavedBy>
<AcDxDwgSummaryDwgRevisionNumber />
<AcDxDwgSummaryDwgTotalEditingTime>
1179
</AcDxDwgSummaryDwgTotalEditingTime>
<AcDxEntityHyperlink />
</My_Data_Extract>
<!-- Stuff deleted from the XML output -->
<!-- ... -->
</DocumentElement>

Subscribe via RSS
Kean,
Is this available through C++?
How to make our custom objects support XML exporting?
Fernando.
Posted by: Fernando Malard | April 09, 2008 at 01:52 AM
Fernando,
I don't think that's currently possible: it doesn't appear to pick up properties exposed through COM, although I haven't tried with a managed wrapper.
Please submit your question via the ADN site for someone to look into.
Regards,
Kean
Posted by: Kean | April 09, 2008 at 01:30 PM
Oh - and this is a managed API, so it can be called from C++. There isn't an unmanaged C++ API, though.
Kean
Posted by: Kean | April 09, 2008 at 01:32 PM
When compiling, I get the following message: The type or namespace name 'DataExtraction' does not exist in the namespace 'Autodesk.AutoCAD' (are you missing an assembly reference?)
Which assembly do I need to add as a reference?
Posted by: Tom | April 09, 2008 at 03:57 PM
Ah yes - I missed a step: you need to add a project reference to AcDx.dll, which can be found in the inc-win32 and inc-x64 folders of the ObjectARX 2009 SDK (as well as being in the AutoCAD 2009 root folder).
Regards,
Kean
Posted by: Kean | April 09, 2008 at 04:05 PM
Hello,
Was the following an error:
IDxExtractionSettings es =
es = new DxExtractionSettings();
Should it have been written like:
IDxExtractionSettings es = new DxExtractionSettings();
Or, doesn't it make any difference?
Thank You
Posted by: Tom | April 09, 2008 at 07:10 PM
Hi Tom,
It was a typo - thanks for spotting it. I've fixed the post.
Regards,
Kean
Posted by: Kean | April 09, 2008 at 09:18 PM
you can filter the properties customized and bring only what you need?
Posted by: wesley | May 14, 2008 at 07:43 PM
I believe so, although I didn't try it.
Kean
Posted by: Kean | May 14, 2008 at 08:46 PM
Hi Kean.
I just popped this into VB and took out the hard coded filenames. I ran it on a drawing created by my automation program, and the only thing I don't see extracted is Xdata.
I'd be interested in figuring out if that could be done. (in the data extraction tool, I know how to do it otherwise)
Actually I also saw something else a little strange... I have a particular type of block which is inserted with varying X-scales so that the length of the block changes. The Attribute references show up under the data for the block, but the specific data for the attribute references themselves does not show up next in the list, like it did for other uniformly scaled blocks. At the moment I don't think this concerns me, I just found it interesting.
Posted by: David Osborne | October 10, 2008 at 11:18 PM
Hi David,
I hadn't tried this with Xdata, but it doesn't fully surprise me that this isn't currently supported.
Xdata content tends to be stored fairly generically - the group codes don't have standardised, human-readable labels - so some logic would be needed to map these to XML elements. Not to say it's very hard to do, but it doesn't surprise me that it hasn't been done.
I hadn't come across non-uniform blocks acting differently. If you're an ADN member it would be great if you could submit it there with a reproducible case.
Thanks,
Kean
Posted by: Kean | October 13, 2008 at 01:46 PM