excel-to-rvt

Note: RVT is the file format. Examples may reference Autodesk® Revit® APIs. Autodesk and Revit are registered trademarks of Autodesk, Inc.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "excel-to-rvt" with this command: npx skills add datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/datadrivenconstruction-ddc-skills-for-ai-agents-in-construction-excel-to-rvt

Excel to RVT Import

Note: RVT is the file format. Examples may reference Autodesk® Revit® APIs. Autodesk and Revit are registered trademarks of Autodesk, Inc.

Business Case

Problem Statement

External data (costs, specifications, classifications) lives in Excel but needs to update Revit:

  • Cost estimates need to link to model elements

  • Classification codes need assignment

  • Custom parameters need population

  • Manual entry is slow and error-prone

Solution

Automated import of Excel data into Revit using the DDC ImportExcelToRevit tool and Dynamo workflows.

Business Value

  • Automation - Batch update thousands of parameters

  • Accuracy - Eliminate manual data entry errors

  • Sync - Keep external data in sync with model

  • Flexibility - Update any writable parameter

Technical Implementation

Methods

  • ImportExcelToRevit CLI - Direct command-line update

  • Dynamo Script - Visual programming approach

  • Revit API - Full programmatic control

ImportExcelToRevit CLI

ImportExcelToRevit.exe <model.rvt> <data.xlsx> [options]

Option Description

-sheet

Excel sheet name

-idcol

Element ID column

-mapping

Parameter mapping file

Python Implementation

import subprocess import pandas as pd from pathlib import Path from typing import Dict, Any, List, Optional, Tuple from dataclasses import dataclass import json

@dataclass class ImportResult: """Result of Excel import to Revit.""" elements_processed: int elements_updated: int elements_failed: int parameters_updated: int errors: List[str]

class ExcelToRevitImporter: """Import Excel data into Revit models."""

def __init__(self, tool_path: str = "ImportExcelToRevit.exe"):
    self.tool_path = Path(tool_path)

def import_data(self, revit_file: str,
                excel_file: str,
                sheet_name: str = "Elements",
                id_column: str = "ElementId",
                parameter_mapping: Dict[str, str] = None) -> ImportResult:
    """Import Excel data into Revit."""

    # Build command
    cmd = [
        str(self.tool_path),
        revit_file,
        excel_file,
        "-sheet", sheet_name,
        "-idcol", id_column
    ]

    # Add mapping file if provided
    if parameter_mapping:
        mapping_file = self._create_mapping_file(parameter_mapping)
        cmd.extend(["-mapping", mapping_file])

    # Execute
    result = subprocess.run(cmd, capture_output=True, text=True)

    # Parse result (format depends on tool)
    return self._parse_result(result)

def _create_mapping_file(self, mapping: Dict[str, str]) -> str:
    """Create temporary mapping file."""
    mapping_path = Path("temp_mapping.json")
    with open(mapping_path, 'w') as f:
        json.dump(mapping, f)
    return str(mapping_path)

def _parse_result(self, result: subprocess.CompletedProcess) -> ImportResult:
    """Parse CLI result."""
    # This is placeholder - actual parsing depends on tool output
    if result.returncode == 0:
        return ImportResult(
            elements_processed=0,
            elements_updated=0,
            elements_failed=0,
            parameters_updated=0,
            errors=[]
        )
    else:
        return ImportResult(
            elements_processed=0,
            elements_updated=0,
            elements_failed=0,
            parameters_updated=0,
            errors=[result.stderr]
        )

class DynamoScriptGenerator: """Generate Dynamo scripts for Revit data import."""

def generate_parameter_update_script(self,
                                     mappings: Dict[str, str],
                                     excel_path: str,
                                     output_path: str) -> str:
    """Generate Dynamo Python script for parameter updates."""

    mappings_json = json.dumps(mappings)

    script = f'''

Dynamo Python Script - Excel to Revit Parameter Update

Generated by DDC

import clr import sys sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\Lib')

clr.AddReference('RevitAPI') clr.AddReference('RevitServices') clr.AddReference('Microsoft.Office.Interop.Excel')

from RevitServices.Persistence import DocumentManager from RevitServices.Transactions import TransactionManager from Autodesk.Revit.DB import * import Microsoft.Office.Interop.Excel as Excel

Configuration

excel_path = r'{excel_path}' mappings = {mappings_json}

Open Excel

excel_app = Excel.ApplicationClass() excel_app.Visible = False workbook = excel_app.Workbooks.Open(excel_path) worksheet = workbook.Worksheets[1]

Get Revit document

doc = DocumentManager.Instance.CurrentDBDocument

Read Excel data

used_range = worksheet.UsedRange rows = used_range.Rows.Count cols = used_range.Columns.Count

Find column indices

headers = {{}} for col in range(1, cols + 1): header = str(worksheet.Cells[1, col].Value2 or '') headers[header] = col

Process rows

TransactionManager.Instance.EnsureInTransaction(doc)

updated_count = 0 error_count = 0

for row in range(2, rows + 1): try: # Get element ID element_id_col = headers.get('ElementId', 1) element_id = int(worksheet.Cells[row, element_id_col].Value2 or 0)

    element = doc.GetElement(ElementId(element_id))
    if not element:
        continue

    # Update mapped parameters
    for excel_col, revit_param in mappings.items():
        if excel_col in headers:
            col_idx = headers[excel_col]
            value = worksheet.Cells[row, col_idx].Value2

            if value is not None:
                param = element.LookupParameter(revit_param)
                if param and not param.IsReadOnly:
                    if param.StorageType == StorageType.Double:
                        param.Set(float(value))
                    elif param.StorageType == StorageType.Integer:
                        param.Set(int(value))
                    elif param.StorageType == StorageType.String:
                        param.Set(str(value))

    updated_count += 1

except Exception as e:
    error_count += 1

TransactionManager.Instance.TransactionTaskDone()

Cleanup

workbook.Close(False) excel_app.Quit()

OUT = f"Updated: {{updated_count}}, Errors: {{error_count}}" '''

    with open(output_path, 'w') as f:
        f.write(script)

    return output_path

def generate_schedule_creator(self,
                              schedule_name: str,
                              category: str,
                              fields: List[str],
                              output_path: str) -> str:
    """Generate script to create Revit schedule from Excel structure."""

    fields_json = json.dumps(fields)

    script = f'''

Dynamo Python Script - Create Schedule

Generated by DDC

import clr clr.AddReference('RevitAPI') clr.AddReference('RevitServices')

from RevitServices.Persistence import DocumentManager from RevitServices.Transactions import TransactionManager from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument fields = {fields_json}

Get category

category = Category.GetCategory(doc, BuiltInCategory.OST_{category})

TransactionManager.Instance.EnsureInTransaction(doc)

Create schedule

schedule = ViewSchedule.CreateSchedule(doc, category.Id) schedule.Name = "{schedule_name}"

Add fields

definition = schedule.Definition

for field_name in fields: # Find schedulable field for sf in definition.GetSchedulableFields(): if sf.GetName(doc) == field_name: definition.AddField(sf) break

TransactionManager.Instance.TransactionTaskDone()

OUT = schedule '''

    with open(output_path, 'w') as f:
        f.write(script)

    return output_path

class ExcelDataValidator: """Validate Excel data before Revit import."""

def __init__(self, revit_elements: pd.DataFrame):
    """Initialize with exported Revit elements."""
    self.revit_data = revit_elements
    self.valid_ids = set(revit_elements['ElementId'].astype(str).tolist())

def validate_import_data(self, import_df: pd.DataFrame,
                         id_column: str = 'ElementId') -> Dict[str, Any]:
    """Validate import data against Revit export."""

    results = {
        'valid': True,
        'total_rows': len(import_df),
        'matching_ids': 0,
        'missing_ids': [],
        'invalid_ids': [],
        'warnings': []
    }

    import_ids = import_df[id_column].astype(str).tolist()

    for import_id in import_ids:
        if import_id in self.valid_ids:
            results['matching_ids'] += 1
        else:
            results['invalid_ids'].append(import_id)

    if results['invalid_ids']:
        results['valid'] = False
        results['warnings'].append(
            f"{len(results['invalid_ids'])} element IDs not found in Revit model"
        )

    results['match_rate'] = round(
        results['matching_ids'] / results['total_rows'] * 100, 1
    ) if results['total_rows'] > 0 else 0

    return results

def check_parameter_types(self, import_df: pd.DataFrame,
                          type_definitions: Dict[str, str]) -> List[str]:
    """Check if values match expected parameter types."""

    errors = []

    for column, expected_type in type_definitions.items():
        if column not in import_df.columns:
            continue

        for idx, value in import_df[column].items():
            if pd.isna(value):
                continue

            if expected_type == 'number':
                try:
                    float(value)
                except ValueError:
                    errors.append(f"Row {idx}: '{column}' should be number, got '{value}'")

            elif expected_type == 'integer':
                try:
                    int(value)
                except ValueError:
                    errors.append(f"Row {idx}: '{column}' should be integer, got '{value}'")

    return errors

Quick Start

Generate Dynamo script

generator = DynamoScriptGenerator()

mappings = { 'OmniClass_Code': 'OmniClass Number', 'Unit_Cost': 'Cost', 'Material_Type': 'Material' }

generator.generate_parameter_update_script( mappings=mappings, excel_path="enriched_data.xlsx", output_path="update_revit.py" )

Validation

Validate before import

validator = ExcelDataValidator(revit_export_df) validation = validator.validate_import_data(import_df)

if validation['valid']: print(f"Ready to import. Match rate: {validation['match_rate']}%") else: print(f"Issues found: {validation['warnings']}")

Complete Workflow

1. Export from Revit

RvtExporter.exe model.rvt complete

2. Load and validate

revit_df = pd.read_excel("model.xlsx") validator = ExcelDataValidator(revit_df)

3. Prepare import data

import_df = pd.read_excel("enriched_data.xlsx") validation = validator.validate_import_data(import_df)

4. Generate update script

if validation['valid']: generator = DynamoScriptGenerator() generator.generate_parameter_update_script( mappings={'Classification': 'OmniClass Number'}, excel_path="enriched_data.xlsx", output_path="apply_updates.py" ) print("Run apply_updates.py in Dynamo to update Revit")

Resources

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

drawing-analyzer

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

cad-to-data

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

dwg-to-excel

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

cost-estimation-resource

No summary provided by upstream source.

Repository SourceNeeds Review