Export Data to XML

Here is another issue of general interest and that arose during the

DevLab in Waltham
last week:

Question: How can I export some Revit model data to an XML file, for instance certain sheet properties?

Answer: That is actually very easy.
All you need to do is:

  • Collect the Revit elements of interest, for instance all sheets.
  • Extract and save the data of interest from them, for instance the sheet number.
  • Iterate over the data collection and export it to XML.

You could of course also skip saving the data in an intermediate container and export it to an external file directly.
Adding the intermediate step might be useful, for instance to sort the data items or add other processing.

Exporting to XML is easy, because the .NET framework includes lots of XML formatting functionality.
It would also be easy to generate your own XML output file by hand, though.

Here is a super simple little ViewSheet data container to use for the intermediate storage:


class SheetData
{
  public bool IsPlaceholder { get; set; }
  public string Name { get; set; }
  public string SheetNumber { get; set; }
 
  public SheetData( ViewSheet v )
  {
    IsPlaceholder = v.IsPlaceholder;
    Name = v.Name;
    SheetNumber = v.SheetNumber;
  }
}

Obviously this data holder is rather overly simplistic, but you can easily add other items of interest to you to it.

I implemented a new Building Coder sample command which performs the steps outlined above making use of this data container class:


[Transaction( TransactionMode.ReadOnly )]
[Regeneration( RegenerationOption.Manual )]
class CmdSheetData : IExternalCommand
{
  public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements )
  {
    UIApplication app = commandData.Application;
    Document doc = app.ActiveUIDocument.Document;
 
    // retrieve all sheets
 
    FilteredElementCollector a
      = new FilteredElementCollector( doc );
 
    a.OfCategory( BuiltInCategory.OST_Sheets );
    a.OfClass( typeof( ViewSheet ) );
 
    // create a collection of all relevant data
 
    List<SheetData> data = new List<SheetData>();
 
    foreach( ViewSheet v in a )
    {
      // create some data for each sheet and add 
      // to some serializable collection called Data
      SheetData item = new SheetData( v );
      data.Add( item );
    }
 
    // write out data collection to xml
 
    XmlTextWriter w = new XmlTextWriter(
      "C:/SheetData.xml", null );
 
    w.Formatting = Formatting.Indented;
    w.WriteStartDocument();
    w.WriteComment( string.Format(
      " SheetData from {0} on {1} by Jeremy ",
      doc.PathName, DateTime.Now ) );
 
    w.WriteStartElement( "ViewSheets" );
 
    foreach( SheetData item in data )
    {
      w.WriteStartElement( "ViewSheet" );
 
      w.WriteElementString( "IsPlaceholder",
        item.IsPlaceholder.ToString() );
 
      w.WriteElementString( "Name", item.Name );
 
      w.WriteElementString( "SheetNumber",
        item.SheetNumber );
 
      w.WriteEndElement();
    }
    w.WriteEndElement();
    w.WriteEndDocument();
    w.Close();
 
    return Result.Succeeded;
  }
}

Here is the XML file resulting from running this command in a simple Revit model:


<?xml version="1.0"?>
<!-- SheetData from C:tmpsheets_and_views.rvt 
     on 2010-06-12 18:16:48 by Jeremy -->
<ViewSheets>
  <ViewSheet>
    <IsPlaceholder>False</IsPlaceholder>
    <Name>Unnamed</Name>
    <SheetNumber>A101</SheetNumber>
  </ViewSheet>
  <ViewSheet>
    <IsPlaceholder>False</IsPlaceholder>
    <Name>Unnamed</Name>
    <SheetNumber>A102</SheetNumber>
  </ViewSheet>
  <ViewSheet>
    <IsPlaceholder>False</IsPlaceholder>
    <Name>Unnamed</Name>
    <SheetNumber>A103</SheetNumber>
  </ViewSheet>
  <ViewSheet>
    <IsPlaceholder>False</IsPlaceholder>
    <Name>Unnamed</Name>
    <SheetNumber>A104</SheetNumber>
  </ViewSheet>
</ViewSheets>

I initially created this as a stand-alone application, and here is the add-in manifest file, source code, and Visual Studio solution for that, compressed in the archive file
SheetData.zip

As said, since it seems useful to keep track of this simple XML exporting functionality for future use as well, I also added the command to The Building Coder samples.
Here is

version 2011.0.72.0
of the complete source code and Visual Studio solution including the new command.
Since I use a

RvtSamples include file

BcSamples.txt to load The Building Coder samples, included in the archive file, I provide no separate add-in manifest files for these commands.


Comments

7 responses to “Export Data to XML”

  1. Paul Gibson Avatar
    Paul Gibson

    Hi Jeremy,
    I am trying to set viewsheet parameters from a text file, and have a mysterious exception upon commit. I have an error handler that does not capture an error, so am at a loss and have begun breaking things apart.
    I read the values from a text file, so my outer loop is a streamreader.ReadLine() call
    Then I loop through my viewSheets collector to find the right sheet. It strikes me that I may be better off using LINQ to find the particular sheet, but cannot find a suitable example. I am assuming that Revit won’t allow a sheet to have a Sheet Number that is not unique (untested assumption for now).
    So here is what I’m doing, but the compiler doesn’t like it. Can you help?
    string[] linearray;
    ViewSheet vQuery;
    FilteredElementCollector Sheets = new
    FilteredElementCollector(doc).OfClass(typeof(ViewSheet));
    var query = from element in Sheets
    where
    element.get_Parameter(KeyParameter.Text).AsString() == linearray[0]
    select element; //linearray is a split (\t) on the ReadLine
    if (query.Count.AsValue() > 0) //doesn’t like this
    vQuery = (ViewSheet) query.ElementAt(0); // I know this is wrong . . . how do I get the actual sheet?
    Thanks for your help!

  2. Dear Paul,
    First you talk about an exception. That is a runtime error.
    Then you say the compiler is complaining. That is a compile time error, and not an exception.
    Anyway, I would suggest that you search for some examples of using the .NET generic templated collection extension method FirstOrDefault in conjunction with a FilteredElementCollector.
    http://lmgtfy.com/?q=FirstOrDefault+FilteredElementCollector
    I use that myself on a regular basis, and I think that does exactly what you need.
    LINQ will not be any better than anything else.
    The only thing that makes a difference performance-wise is whether you use the Revit filtered element collector functionality, which is very fast, or something based on .NET that post processes the results of the former. That is significantly slower.
    Cheers, Jeremy.

  3. Frank Halliday Avatar
    Frank Halliday

    Hi Jeremy,
    I am looking to read xml data into a revit addin. Are there any Revit specific tutorials I could possibly read up on?
    Cheers,
    Frank

  4. Dear Frank,
    There are about umpteen zillion .NET XML libraries you can use, plus this functionality is provided by the standard .NET framework:
    http://lmgtfy.com/?q=.NET+XML+library
    Cheers, Jeremy.

  5. Frank Halliday Avatar
    Frank Halliday

    thanx jeremy, thats C# power I love it

  6. frank halliday Avatar
    frank halliday

    Hi Jeremy,
    Why do we need to set the transaction property to read-only? How can I edit the family doc to acquire it’s path then famdoc.close() it in readonly mode as this causes an exception.
    cheers
    fabs

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading