ifc-to-excel
Convert IFC files (2x3, 4x1, 4x3) to Excel databases using IfcExporter CLI. Extract BIM data, properties, and geometry without proprietary software.
Install / Use
npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill ifc-to-excelInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
Data & AnalyticsSupported Platforms
Our assessment of ifc-to-excel
ifc-to-excel scores 91/100 on our quality scale, 245th of 585 Data & Analytics skills we index (top 42%).
Its SKILL.md is 17 KB long, well organised into 37 sections with 8 code examples: a thorough specification that gives an agent plenty to work with.
It has 333 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 44 days ago, so ifc-to-excel is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
ifc-to-excel compared with similar skills
All 4 of these similar skills score higher than ifc-to-excel; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| ifc-to-excel (this skill)by datadrivenconstruction | 91 | 333 | 44d ago | SKILL.md |
| Agent-Reachby Panniantong | 100 | 91.2k | 19d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.4k | today | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 85.7k | today | MCP Server |
| crawl4aiby unclecode | 100 | 84.8k | today | MCP Server |
Frequently asked questions
- How do I install ifc-to-excel?
- Run
npx skills add datadrivenconstruction/DDC_Skills_for_AI_Agents_in_Construction --skill ifc-to-excel. The install tabs above show the steps for each supported agent. - Which AI agents does ifc-to-excel work with?
- It is written for Zed, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is ifc-to-excel safe to use?
- It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is ifc-to-excel still maintained?
- The repository was last updated 44 days ago, so ifc-to-excel is actively maintained.
Skill content
View source on GitHubname: "ifc-to-excel" description: "Convert IFC files (2x3, 4x1, 4x3) to Excel databases using IfcExporter CLI. Extract BIM data, properties, and geometry without proprietary software." homepage: "https://datadrivenconstruction.io" metadata: {"openclaw":{"emoji":"📋","os":["darwin","linux","win32"],"homepage":"https://datadrivenconstruction.io","requires":{"bins":["python3"],"anyBins":["IfcExporter","IfcConvert"]}}}
IFC to Excel Conversion
Business Case
Problem Statement
IFC (Industry Foundation Classes) is the open BIM standard, but:
- Reading IFC requires specialized software
- Property extraction needs programming knowledge
- Batch processing is manual and time-consuming
- Integration with analytics tools is complex
Solution
IfcExporter.exe converts IFC files to structured Excel databases, making BIM data accessible for analysis, validation, and reporting.
Business Value
- Open standard - Process any IFC file (2x3, 4x, 4.3)
- No licenses - Works offline without BIM software
- Data extraction - All properties, quantities, materials
- 3D geometry - Export to Collada DAE format
- Pipeline ready - Integrate with ETL workflows
Technical Implementation
CLI Syntax
IfcExporter.exe <input_ifc> [options]
Supported IFC Versions
| Version | Schema | Description | |---------|--------|-------------| | IFC2x3 | MVD | Most common exchange format | | IFC4 | ADD1 | Enhanced properties | | IFC4x1 | Alignment | Infrastructure support | | IFC4x3 | Latest | Full infrastructure |
Output Formats
| Output | Description |
|--------|-------------|
| .xlsx | Excel database with elements and properties |
| .dae | Collada 3D geometry with matching IDs |
Options
| Option | Description |
|--------|-------------|
| bbox | Include element bounding boxes |
| -no-xlsx | Skip Excel export |
| -no-collada | Skip 3D geometry export |
Examples
# Basic conversion (XLSX + DAE)
IfcExporter.exe "C:\Models\Building.ifc"
# With bounding boxes
IfcExporter.exe "C:\Models\Building.ifc" bbox
# Excel only (no 3D geometry)
IfcExporter.exe "C:\Models\Building.ifc" -no-collada
# Batch processing
for /R "C:\IFC_Models" %f in (*.ifc) do IfcExporter.exe "%f" bbox
Python Integration
import subprocess
import pandas as pd
from pathlib import Path
from typing import List, Optional, Dict, Any, Set
from dataclasses import dataclass, field
from enum import Enum
import json
class IFCVersion(Enum):
"""IFC schema versions."""
IFC2X3 = "IFC2X3"
IFC4 = "IFC4"
IFC4X1 = "IFC4X1"
IFC4X3 = "IFC4X3"
class IFCEntityType(Enum):
"""Common IFC entity types."""
IFCWALL = "IfcWall"
IFCWALLSTANDARDCASE = "IfcWallStandardCase"
IFCSLAB = "IfcSlab"
IFCCOLUMN = "IfcColumn"
IFCBEAM = "IfcBeam"
IFCDOOR = "IfcDoor"
IFCWINDOW = "IfcWindow"
IFCROOF = "IfcRoof"
IFCSTAIR = "IfcStair"
IFCRAILING = "IfcRailing"
IFCFURNISHINGELEMENT = "IfcFurnishingElement"
IFCSPACE = "IfcSpace"
IFCBUILDINGSTOREY = "IfcBuildingStorey"
IFCBUILDING = "IfcBuilding"
IFCSITE = "IfcSite"
@dataclass
class IFCElement:
"""Represents an IFC element."""
global_id: str
ifc_type: str
name: str
description: Optional[str]
object_type: Optional[str]
level: Optional[str]
# Quantities
area: Optional[float] = None
volume: Optional[float] = None
length: Optional[float] = None
height: Optional[float] = None
width: Optional[float] = None
# Bounding box (if exported)
bbox_min_x: Optional[float] = None
bbox_min_y: Optional[float] = None
bbox_min_z: Optional[float] = None
bbox_max_x: Optional[float] = None
bbox_max_y: Optional[float] = None
bbox_max_z: Optional[float] = None
# Properties
properties: Dict[str, Any] = field(default_factory=dict)
materials: List[str] = field(default_factory=list)
@dataclass
class IFCProperty:
"""Represents an IFC property."""
pset_name: str
property_name: str
value: Any
value_type: str
@dataclass
class IFCMaterial:
"""Represents an IFC material."""
name: str
category: Optional[str]
thickness: Optional[float]
layer_position: Optional[int]
class IFCExporter:
"""IFC to Excel converter using DDC IfcExporter CLI."""
def __init__(self, exporter_path: str = "IfcExporter.exe"):
self.exporter = Path(exporter_path)
if not self.exporter.exists():
raise FileNotFoundError(f"IfcExporter not found: {exporter_path}")
def convert(self, ifc_file: str,
include_bbox: bool = True,
export_xlsx: bool = True,
export_collada: bool = True) -> Path:
"""Convert IFC file to Excel."""
ifc_path = Path(ifc_file)
if not ifc_path.exists():
raise FileNotFoundError(f"IFC file not found: {ifc_file}")
cmd = [str(self.exporter), str(ifc_path)]
if include_bbox:
cmd.append("bbox")
if not export_xlsx:
cmd.append("-no-xlsx")
if not export_collada:
cmd.append("-no-collada")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"Export failed: {result.stderr}")
return ifc_path.with_suffix('.xlsx')
def batch_convert(self, folder: str,
include_subfolders: bool = True,
include_bbox: bool = True) -> List[Dict[str, Any]]:
"""Convert all IFC files in folder."""
folder_path = Path(folder)
pattern = "**/*.ifc" if include_subfolders else "*.ifc"
results = []
for ifc_file in folder_path.glob(pattern):
try:
output = self.convert(str(ifc_file), include_bbox)
results.append({
'input': str(ifc_file),
'output': str(output),
'status': 'success'
})
print(f"✓ Converted: {ifc_file.name}")
except Exception as e:
results.append({
'input': str(ifc_file),
'output': None,
'status': 'failed',
'error': str(e)
})
print(f"✗ Failed: {ifc_file.name} - {e}")
return results
def read_elements(self, xlsx_file: str) -> pd.DataFrame:
"""Read converted Excel as DataFrame."""
return pd.read_excel(xlsx_file, sheet_name="Elements")
def get_element_types(self, xlsx_file: str) -> pd.DataFrame:
"""Get element type summary."""
df = self.read_elements(xlsx_file)
if 'IfcType' not in df.columns:
raise ValueError("IfcType column not found")
summary = df.groupby('IfcType').agg({
'GlobalId': 'count',
'Volume': 'sum' if 'Volume' in df.columns else 'count',
'Area': 'sum' if 'Area' in df.columns else 'count'
}).reset_index()
summary.columns = ['IFC_Type', 'Count', 'Total_Volume', 'Total_Area']
return summary.sort_values('Count', ascending=False)
def get_levels(self, xlsx_file: str) -> pd.DataFrame:
"""Get building level summary."""
df = self.read_elements(xlsx_file)
level_col = None
for col in ['Level', 'BuildingStorey', 'IfcBuildingStorey']:
if col in df.columns:
level_col = col
break
if level_col is None:
return pd.DataFrame(columns=['Level', 'Element_Count'])
summary = df.groupby(level_col).agg({
'GlobalId': 'count'
}).reset_index()
summary.columns = ['Level', 'Element_Count']
return summary
def get_materials(self, xlsx_file: str) -> pd.DataFrame:
"""Get material summary."""
df = self.read_elements(xlsx_file)
if 'Material' not in df.columns:
return pd.DataFrame(columns=['Material', 'Count'])
summary = df.groupby('Material').agg({
'GlobalId': 'count'
}).reset_index()
summary.columns = ['Material', 'Element_Count']
return summary.sort_values('Element_Count', ascending=False)
def get_quantities(self, xlsx_file: str,
group_by: str = 'IfcType') -> pd.DataFrame:
"""Get quantity takeoff summary."""
df = self.read_elements(xlsx_file)
if group_by not in df.columns:
raise ValueError(f"Column {group_by} not found")
agg_dict = {'GlobalId': 'count'}
# Add numeric columns for aggregation
numeric_cols = ['Volume', 'Area', 'Length', 'Width', 'Height']
for col in numeric_cols:
if col in df.columns:
agg_dict[col] = 'sum'
summary = df.groupby(group_by).agg(agg_dict).reset_index()
return summary
def filter_by_type(self, xlsx_file: str,
ifc_types: List[str]) -> pd.DataFrame:
"""Filter elements by IFC type."""
df = self.read_elements(xlsx_file)
return df[df['IfcType'].isin(ifc_types)]
def get_properties(self, xlsx_file: str,
element_id: str) -> Dict[str, Any]:
"""Get all properties for specific element."""
df = self.read_elements(xlsx_file)
element = df[df['GlobalId'] == element_id]
if element.empty:
return {}
# Convert row to dictionary, excluding NaN values
props = element.iloc[0].dropna().to_dict()
return props
def validate_ifc_data(self, xlsx_file: str) -> Dict[str, Any]:
"""Validate IFC data quality."""
df = self.read_elements(xlsx_file)
validation = {
'total_elements': len(df),
'issues': []
}
# Check for missing GlobalIds
if 'GlobalId' in df.columns:
missing_ids = df['GlobalId'].isna().sum()
if missing_ids > 0:
validation['issues'].append(f"{missing_ids} elements missing GlobalId")
# Check for missing names
if 'Name' in df.columns:
missing_names = df['Name'].isna().sum()
if missing_names > 0:
validation['issues'].append(f"{missing_names} elements missing Name")
# Check for zero quantities
for col in ['Volume', 'Area']:
if col in df.columns:
zero_qty = (df[col] == 0).sum()
if zero_qty > 0:
validation['issues'].append(f"{zero_qty} elements with zero {col}")
# Check for duplicate GlobalIds
if 'GlobalId' in df.columns:
duplicates = df['GlobalId'].duplicated().sum()
if duplicates > 0:
validation['issues'].append(f"{duplicates} duplicate GlobalIds")
validation['is_valid'] = len(validation['issues']) == 0
return validation
class IFCQuantityTakeoff:
"""Quantity takeoff from IFC data."""
def __init__(self, exporter: IFCExporter):
self.exporter = exporter
def generate_qto(self, ifc_file: str) -> Dict[str, pd.DataFrame]:
"""Generate complete quantity takeoff."""
xlsx = self.exporter.convert(ifc_file, include_bbox=True)
df = self.exporter.read_elements(str(xlsx))
qto = {}
# Walls
walls = df[df['IfcType'].str.contains('Wall', case=False, na=False)]
if not walls.empty:
qto['Walls'] = self._summarize_elements(walls, 'Type Name')
# Slabs
slabs = df[df['IfcType'].str.contains('Slab', case=False, na=False)]
if not slabs.empty:
qto['Slabs'] = self._summarize_elements(slabs, 'Type Name')
# Columns
columns = df[df['IfcType'].str.contains('Column', case=False, na=False)]
if not columns.empty:
qto['Columns'] = self._summarize_elements(columns, 'Type Name')
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
91.2kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
74.4kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
Scrapling
85.7k🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
crawl4ai
84.8kOpen-source web crawler and scraper for LLMs and AI agents: any website into clean, LLM-ready Markdown. Run it yourself, or use Crawl4AI Cloud with one key.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
