{
  "schemaVersion": "1.0",
  "item": {
    "slug": "dgn-to-excel",
    "name": "Dgn To Excel",
    "source": "tencent",
    "type": "skill",
    "category": "数据分析",
    "sourceUrl": "https://clawhub.ai/datadrivenconstruction/dgn-to-excel",
    "canonicalUrl": "https://clawhub.ai/datadrivenconstruction/dgn-to-excel",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/dgn-to-excel",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=dgn-to-excel",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "claw.json",
      "instructions.md",
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/dgn-to-excel"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/dgn-to-excel",
    "agentPageUrl": "https://openagent3.xyz/skills/dgn-to-excel/agent",
    "manifestUrl": "https://openagent3.xyz/skills/dgn-to-excel/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/dgn-to-excel/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Problem Statement",
        "body": "DGN files are common in infrastructure and civil engineering:\n\nTransportation and highway design\nBridge and tunnel projects\nUtility networks\nRail infrastructure\n\nExtracting structured data from DGN files for analysis and reporting can be challenging."
      },
      {
        "title": "Solution",
        "body": "Convert DGN files to structured Excel databases, supporting both v7 and v8 formats."
      },
      {
        "title": "Business Value",
        "body": "Infrastructure support - Civil engineering focused\nLegacy format support - V7 and V8 DGN files\nData extraction - Levels, cells, text, geometry\nBatch processing - Process multiple files\nStructured output - Excel format for analysis"
      },
      {
        "title": "CLI Syntax",
        "body": "DgnExporter.exe <input_dgn>"
      },
      {
        "title": "Supported Versions",
        "body": "VersionDescriptionV7 DGNLegacy MicroStation format (pre-V8)V8 DGNModern MicroStation formatV8i DGNMicroStation V8i format"
      },
      {
        "title": "Output Format",
        "body": "OutputDescription.xlsxExcel database with all elements"
      },
      {
        "title": "Examples",
        "body": "# Basic conversion\nDgnExporter.exe \"C:\\Projects\\Bridge.dgn\"\n\n# Batch processing\nfor /R \"C:\\Infrastructure\" %f in (*.dgn) do DgnExporter.exe \"%f\"\n\n# PowerShell batch\nGet-ChildItem \"C:\\Projects\\*.dgn\" -Recurse | ForEach-Object {\n    & \"C:\\DDC\\DgnExporter.exe\" $_.FullName\n}"
      },
      {
        "title": "Python Integration",
        "body": "import subprocess\nimport pandas as pd\nfrom pathlib import Path\nfrom typing import List, Optional, Dict, Any\nfrom dataclasses import dataclass\nfrom enum import Enum\n\n\nclass DGNElementType(Enum):\n    \"\"\"DGN element types.\"\"\"\n    CELL_HEADER = 2\n    LINE = 3\n    LINE_STRING = 4\n    SHAPE = 6\n    TEXT_NODE = 7\n    CURVE = 11\n    COMPLEX_CHAIN = 12\n    COMPLEX_SHAPE = 14\n    ELLIPSE = 15\n    ARC = 16\n    TEXT = 17\n    SURFACE = 18\n    SOLID = 19\n    BSPLINE_CURVE = 21\n    POINT_STRING = 22\n    DIMENSION = 33\n    SHARED_CELL = 35\n\n\n@dataclass\nclass DGNElement:\n    \"\"\"Represents a DGN element.\"\"\"\n    element_id: int\n    element_type: int\n    type_name: str\n    level: int\n    color: int\n    weight: int\n    style: int\n\n    # Geometry\n    range_low_x: Optional[float] = None\n    range_low_y: Optional[float] = None\n    range_low_z: Optional[float] = None\n    range_high_x: Optional[float] = None\n    range_high_y: Optional[float] = None\n    range_high_z: Optional[float] = None\n\n    # Cell/Text specific\n    cell_name: Optional[str] = None\n    text_content: Optional[str] = None\n\n\n@dataclass\nclass DGNLevel:\n    \"\"\"Represents a DGN level.\"\"\"\n    number: int\n    name: str\n    is_displayed: bool\n    is_frozen: bool\n    element_count: int\n\n\nclass DGNExporter:\n    \"\"\"DGN to Excel converter using DDC DgnExporter CLI.\"\"\"\n\n    def __init__(self, exporter_path: str = \"DgnExporter.exe\"):\n        self.exporter = Path(exporter_path)\n        if not self.exporter.exists():\n            raise FileNotFoundError(f\"DgnExporter not found: {exporter_path}\")\n\n    def convert(self, dgn_file: str) -> Path:\n        \"\"\"Convert DGN file to Excel.\"\"\"\n        dgn_path = Path(dgn_file)\n        if not dgn_path.exists():\n            raise FileNotFoundError(f\"DGN file not found: {dgn_file}\")\n\n        cmd = [str(self.exporter), str(dgn_path)]\n        result = subprocess.run(cmd, capture_output=True, text=True)\n\n        if result.returncode != 0:\n            raise RuntimeError(f\"Export failed: {result.stderr}\")\n\n        return dgn_path.with_suffix('.xlsx')\n\n    def batch_convert(self, folder: str,\n                      include_subfolders: bool = True) -> List[Dict[str, Any]]:\n        \"\"\"Convert all DGN files in folder.\"\"\"\n        folder_path = Path(folder)\n        pattern = \"**/*.dgn\" if include_subfolders else \"*.dgn\"\n\n        results = []\n        for dgn_file in folder_path.glob(pattern):\n            try:\n                output = self.convert(str(dgn_file))\n                results.append({\n                    'input': str(dgn_file),\n                    'output': str(output),\n                    'status': 'success'\n                })\n                print(f\"✓ Converted: {dgn_file.name}\")\n            except Exception as e:\n                results.append({\n                    'input': str(dgn_file),\n                    'output': None,\n                    'status': 'failed',\n                    'error': str(e)\n                })\n                print(f\"✗ Failed: {dgn_file.name} - {e}\")\n\n        return results\n\n    def read_elements(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Read converted Excel as DataFrame.\"\"\"\n        return pd.read_excel(xlsx_file, sheet_name=\"Elements\")\n\n    def get_levels(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get level summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        if 'Level' not in df.columns:\n            raise ValueError(\"Level column not found\")\n\n        summary = df.groupby('Level').agg({\n            'ElementId': 'count'\n        }).reset_index()\n        summary.columns = ['Level', 'Element_Count']\n        return summary.sort_values('Level')\n\n    def get_element_types(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get element type statistics.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        type_col = 'ElementType' if 'ElementType' in df.columns else 'Type'\n        if type_col not in df.columns:\n            return pd.DataFrame()\n\n        summary = df.groupby(type_col).agg({\n            'ElementId': 'count'\n        }).reset_index()\n        summary.columns = ['Element_Type', 'Count']\n        return summary.sort_values('Count', ascending=False)\n\n    def get_cells(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get cell references (similar to blocks in DWG).\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        # Filter to cell elements\n        cells = df[df['ElementType'].isin([2, 35])]  # CELL_HEADER, SHARED_CELL\n\n        if cells.empty or 'CellName' not in cells.columns:\n            return pd.DataFrame(columns=['Cell_Name', 'Count'])\n\n        summary = cells.groupby('CellName').agg({\n            'ElementId': 'count'\n        }).reset_index()\n        summary.columns = ['Cell_Name', 'Count']\n        return summary.sort_values('Count', ascending=False)\n\n    def get_text_content(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Extract all text from DGN.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        # Filter to text elements\n        text_types = [7, 17]  # TEXT_NODE, TEXT\n        texts = df[df['ElementType'].isin(text_types)]\n\n        if 'TextContent' in texts.columns:\n            return texts[['ElementId', 'Level', 'TextContent']].copy()\n        return texts[['ElementId', 'Level']].copy()\n\n    def get_statistics(self, xlsx_file: str) -> Dict[str, Any]:\n        \"\"\"Get comprehensive DGN statistics.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        stats = {\n            'total_elements': len(df),\n            'levels_used': df['Level'].nunique() if 'Level' in df.columns else 0,\n            'element_types': df['ElementType'].nunique() if 'ElementType' in df.columns else 0\n        }\n\n        # Calculate extents\n        for coord in ['X', 'Y', 'Z']:\n            low_col = f'RangeLow{coord}'\n            high_col = f'RangeHigh{coord}'\n            if low_col in df.columns and high_col in df.columns:\n                stats[f'min_{coord.lower()}'] = df[low_col].min()\n                stats[f'max_{coord.lower()}'] = df[high_col].max()\n\n        return stats\n\n\nclass DGNAnalyzer:\n    \"\"\"Advanced DGN analysis for infrastructure projects.\"\"\"\n\n    def __init__(self, exporter: DGNExporter):\n        self.exporter = exporter\n\n    def analyze_infrastructure(self, dgn_file: str) -> Dict[str, Any]:\n        \"\"\"Analyze DGN for infrastructure elements.\"\"\"\n        xlsx = self.exporter.convert(dgn_file)\n        df = self.exporter.read_elements(str(xlsx))\n\n        analysis = {\n            'file': dgn_file,\n            'statistics': self.exporter.get_statistics(str(xlsx)),\n            'levels': self.exporter.get_levels(str(xlsx)).to_dict('records'),\n            'element_types': self.exporter.get_element_types(str(xlsx)).to_dict('records'),\n            'cells': self.exporter.get_cells(str(xlsx)).to_dict('records')\n        }\n\n        # Identify infrastructure-specific elements\n        if 'ElementType' in df.columns:\n            # Lines and shapes (often roads, boundaries)\n            lines = df[df['ElementType'].isin([3, 4, 6, 14])].shape[0]\n            analysis['linear_elements'] = lines\n\n            # Complex elements (often structures)\n            complex_elements = df[df['ElementType'].isin([12, 14, 18, 19])].shape[0]\n            analysis['complex_elements'] = complex_elements\n\n            # Annotation elements\n            annotations = df[df['ElementType'].isin([7, 17, 33])].shape[0]\n            analysis['annotations'] = annotations\n\n        return analysis\n\n    def compare_revisions(self, dgn1: str, dgn2: str) -> Dict[str, Any]:\n        \"\"\"Compare two DGN revisions.\"\"\"\n        xlsx1 = self.exporter.convert(dgn1)\n        xlsx2 = self.exporter.convert(dgn2)\n\n        df1 = self.exporter.read_elements(str(xlsx1))\n        df2 = self.exporter.read_elements(str(xlsx2))\n\n        levels1 = set(df1['Level'].unique()) if 'Level' in df1.columns else set()\n        levels2 = set(df2['Level'].unique()) if 'Level' in df2.columns else set()\n\n        return {\n            'revision1': dgn1,\n            'revision2': dgn2,\n            'element_count_diff': len(df2) - len(df1),\n            'levels_added': list(levels2 - levels1),\n            'levels_removed': list(levels1 - levels2),\n            'common_levels': len(levels1 & levels2)\n        }\n\n    def extract_coordinates(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Extract element coordinates for GIS integration.\"\"\"\n        df = self.exporter.read_elements(xlsx_file)\n\n        coord_cols = ['ElementId', 'Level', 'ElementType']\n        for col in ['RangeLowX', 'RangeLowY', 'RangeLowZ',\n                    'RangeHighX', 'RangeHighY', 'RangeHighZ',\n                    'CenterX', 'CenterY', 'CenterZ']:\n            if col in df.columns:\n                coord_cols.append(col)\n\n        return df[coord_cols].copy()\n\n\nclass DGNLevelManager:\n    \"\"\"Manage DGN level structures.\"\"\"\n\n    def __init__(self, exporter: DGNExporter):\n        self.exporter = exporter\n\n    def get_level_map(self, xlsx_file: str) -> Dict[int, str]:\n        \"\"\"Create level number to name mapping.\"\"\"\n        df = self.exporter.read_elements(xlsx_file)\n\n        if 'Level' not in df.columns:\n            return {}\n\n        # MicroStation levels are typically numbered 1-63 (V7) or unlimited (V8)\n        level_map = {}\n        for level in df['Level'].unique():\n            level_map[int(level)] = f\"Level_{level}\"\n\n        return level_map\n\n    def filter_by_levels(self, xlsx_file: str,\n                         levels: List[int]) -> pd.DataFrame:\n        \"\"\"Filter elements by level numbers.\"\"\"\n        df = self.exporter.read_elements(xlsx_file)\n        return df[df['Level'].isin(levels)]\n\n    def get_level_usage_report(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Generate level usage report.\"\"\"\n        df = self.exporter.read_elements(xlsx_file)\n\n        if 'Level' not in df.columns or 'ElementType' not in df.columns:\n            return pd.DataFrame()\n\n        # Cross-tabulate levels and element types\n        report = pd.crosstab(df['Level'], df['ElementType'], margins=True)\n        return report\n\n\n# Convenience functions\ndef convert_dgn_to_excel(dgn_file: str,\n                         exporter_path: str = \"DgnExporter.exe\") -> str:\n    \"\"\"Quick conversion of DGN to Excel.\"\"\"\n    exporter = DGNExporter(exporter_path)\n    output = exporter.convert(dgn_file)\n    return str(output)\n\n\ndef analyze_dgn(dgn_file: str,\n                exporter_path: str = \"DgnExporter.exe\") -> Dict[str, Any]:\n    \"\"\"Analyze DGN file and return summary.\"\"\"\n    exporter = DGNExporter(exporter_path)\n    analyzer = DGNAnalyzer(exporter)\n    return analyzer.analyze_infrastructure(dgn_file)"
      },
      {
        "title": "Excel Sheets",
        "body": "SheetContentElementsAll DGN elements with propertiesLevelsLevel definitionsCellsCell library"
      },
      {
        "title": "Element Columns",
        "body": "ColumnTypeDescriptionElementIdintUnique element IDElementTypeintType code (3=Line, 17=Text, etc.)LevelintLevel numberColorintColor indexWeightintLine weightStyleintLine styleRangeLowX/Y/ZfloatBounding box minimumRangeHighX/Y/ZfloatBounding box maximumCellNamestringCell name (for cell elements)TextContentstringText content (for text elements)"
      },
      {
        "title": "Quick Start",
        "body": "# Initialize exporter\nexporter = DGNExporter(\"C:/DDC/DgnExporter.exe\")\n\n# Convert DGN to Excel\nxlsx = exporter.convert(\"C:/Projects/Highway.dgn\")\nprint(f\"Output: {xlsx}\")\n\n# Read elements\ndf = exporter.read_elements(str(xlsx))\nprint(f\"Total elements: {len(df)}\")\n\n# Get level statistics\nlevels = exporter.get_levels(str(xlsx))\nprint(levels)\n\n# Get element types\ntypes = exporter.get_element_types(str(xlsx))\nprint(types)"
      },
      {
        "title": "1. Infrastructure Analysis",
        "body": "exporter = DGNExporter()\nanalyzer = DGNAnalyzer(exporter)\n\nanalysis = analyzer.analyze_infrastructure(\"highway.dgn\")\nprint(f\"Total elements: {analysis['statistics']['total_elements']}\")\nprint(f\"Linear elements: {analysis['linear_elements']}\")\nprint(f\"Annotations: {analysis['annotations']}\")"
      },
      {
        "title": "2. Level Audit",
        "body": "exporter = DGNExporter()\nxlsx = exporter.convert(\"bridge.dgn\")\nlevels = exporter.get_levels(str(xlsx))\n\n# Check for unused standard levels\nfor idx, row in levels.iterrows():\n    print(f\"Level {row['Level']}: {row['Element_Count']} elements\")"
      },
      {
        "title": "3. GIS Integration",
        "body": "analyzer = DGNAnalyzer(exporter)\nxlsx = exporter.convert(\"utilities.dgn\")\ncoords = analyzer.extract_coordinates(str(xlsx))\n\n# Export for GIS\ncoords.to_csv(\"coordinates.csv\", index=False)"
      },
      {
        "title": "4. Revision Comparison",
        "body": "analyzer = DGNAnalyzer(exporter)\ndiff = analyzer.compare_revisions(\"rev1.dgn\", \"rev2.dgn\")\nprint(f\"Elements changed: {diff['element_count_diff']}\")"
      },
      {
        "title": "Integration with DDC Pipeline",
        "body": "# Infrastructure pipeline: DGN → Excel → Analysis\nfrom dgn_exporter import DGNExporter, DGNAnalyzer\n\n# 1. Convert DGN\nexporter = DGNExporter(\"C:/DDC/DgnExporter.exe\")\nxlsx = exporter.convert(\"highway_project.dgn\")\n\n# 2. Analyze structure\nstats = exporter.get_statistics(str(xlsx))\nprint(f\"Elements: {stats['total_elements']}\")\nprint(f\"Levels: {stats['levels_used']}\")\n\n# 3. Extract for GIS\nanalyzer = DGNAnalyzer(exporter)\ncoords = analyzer.extract_coordinates(str(xlsx))\ncoords.to_csv(\"for_gis.csv\", index=False)"
      },
      {
        "title": "Best Practices",
        "body": "Check version - V7 and V8 have different capabilities\nReference files - Process all reference files separately\nLevel mapping - Document level standards for your organization\nCoordinate systems - Verify units and coordinate systems\nCell libraries - Export cells separately if needed"
      },
      {
        "title": "Resources",
        "body": "GitHub: cad2data Pipeline\nDDC Book: Chapter 2.4 - CAD Data Extraction\nMicroStation: Infrastructure-focused CAD software"
      }
    ],
    "body": "DGN to Excel Conversion\nBusiness Case\nProblem Statement\n\nDGN files are common in infrastructure and civil engineering:\n\nTransportation and highway design\nBridge and tunnel projects\nUtility networks\nRail infrastructure\n\nExtracting structured data from DGN files for analysis and reporting can be challenging.\n\nSolution\n\nConvert DGN files to structured Excel databases, supporting both v7 and v8 formats.\n\nBusiness Value\nInfrastructure support - Civil engineering focused\nLegacy format support - V7 and V8 DGN files\nData extraction - Levels, cells, text, geometry\nBatch processing - Process multiple files\nStructured output - Excel format for analysis\nTechnical Implementation\nCLI Syntax\nDgnExporter.exe <input_dgn>\n\nSupported Versions\nVersion\tDescription\nV7 DGN\tLegacy MicroStation format (pre-V8)\nV8 DGN\tModern MicroStation format\nV8i DGN\tMicroStation V8i format\nOutput Format\nOutput\tDescription\n.xlsx\tExcel database with all elements\nExamples\n# Basic conversion\nDgnExporter.exe \"C:\\Projects\\Bridge.dgn\"\n\n# Batch processing\nfor /R \"C:\\Infrastructure\" %f in (*.dgn) do DgnExporter.exe \"%f\"\n\n# PowerShell batch\nGet-ChildItem \"C:\\Projects\\*.dgn\" -Recurse | ForEach-Object {\n    & \"C:\\DDC\\DgnExporter.exe\" $_.FullName\n}\n\nPython Integration\nimport subprocess\nimport pandas as pd\nfrom pathlib import Path\nfrom typing import List, Optional, Dict, Any\nfrom dataclasses import dataclass\nfrom enum import Enum\n\n\nclass DGNElementType(Enum):\n    \"\"\"DGN element types.\"\"\"\n    CELL_HEADER = 2\n    LINE = 3\n    LINE_STRING = 4\n    SHAPE = 6\n    TEXT_NODE = 7\n    CURVE = 11\n    COMPLEX_CHAIN = 12\n    COMPLEX_SHAPE = 14\n    ELLIPSE = 15\n    ARC = 16\n    TEXT = 17\n    SURFACE = 18\n    SOLID = 19\n    BSPLINE_CURVE = 21\n    POINT_STRING = 22\n    DIMENSION = 33\n    SHARED_CELL = 35\n\n\n@dataclass\nclass DGNElement:\n    \"\"\"Represents a DGN element.\"\"\"\n    element_id: int\n    element_type: int\n    type_name: str\n    level: int\n    color: int\n    weight: int\n    style: int\n\n    # Geometry\n    range_low_x: Optional[float] = None\n    range_low_y: Optional[float] = None\n    range_low_z: Optional[float] = None\n    range_high_x: Optional[float] = None\n    range_high_y: Optional[float] = None\n    range_high_z: Optional[float] = None\n\n    # Cell/Text specific\n    cell_name: Optional[str] = None\n    text_content: Optional[str] = None\n\n\n@dataclass\nclass DGNLevel:\n    \"\"\"Represents a DGN level.\"\"\"\n    number: int\n    name: str\n    is_displayed: bool\n    is_frozen: bool\n    element_count: int\n\n\nclass DGNExporter:\n    \"\"\"DGN to Excel converter using DDC DgnExporter CLI.\"\"\"\n\n    def __init__(self, exporter_path: str = \"DgnExporter.exe\"):\n        self.exporter = Path(exporter_path)\n        if not self.exporter.exists():\n            raise FileNotFoundError(f\"DgnExporter not found: {exporter_path}\")\n\n    def convert(self, dgn_file: str) -> Path:\n        \"\"\"Convert DGN file to Excel.\"\"\"\n        dgn_path = Path(dgn_file)\n        if not dgn_path.exists():\n            raise FileNotFoundError(f\"DGN file not found: {dgn_file}\")\n\n        cmd = [str(self.exporter), str(dgn_path)]\n        result = subprocess.run(cmd, capture_output=True, text=True)\n\n        if result.returncode != 0:\n            raise RuntimeError(f\"Export failed: {result.stderr}\")\n\n        return dgn_path.with_suffix('.xlsx')\n\n    def batch_convert(self, folder: str,\n                      include_subfolders: bool = True) -> List[Dict[str, Any]]:\n        \"\"\"Convert all DGN files in folder.\"\"\"\n        folder_path = Path(folder)\n        pattern = \"**/*.dgn\" if include_subfolders else \"*.dgn\"\n\n        results = []\n        for dgn_file in folder_path.glob(pattern):\n            try:\n                output = self.convert(str(dgn_file))\n                results.append({\n                    'input': str(dgn_file),\n                    'output': str(output),\n                    'status': 'success'\n                })\n                print(f\"✓ Converted: {dgn_file.name}\")\n            except Exception as e:\n                results.append({\n                    'input': str(dgn_file),\n                    'output': None,\n                    'status': 'failed',\n                    'error': str(e)\n                })\n                print(f\"✗ Failed: {dgn_file.name} - {e}\")\n\n        return results\n\n    def read_elements(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Read converted Excel as DataFrame.\"\"\"\n        return pd.read_excel(xlsx_file, sheet_name=\"Elements\")\n\n    def get_levels(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get level summary.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        if 'Level' not in df.columns:\n            raise ValueError(\"Level column not found\")\n\n        summary = df.groupby('Level').agg({\n            'ElementId': 'count'\n        }).reset_index()\n        summary.columns = ['Level', 'Element_Count']\n        return summary.sort_values('Level')\n\n    def get_element_types(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get element type statistics.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        type_col = 'ElementType' if 'ElementType' in df.columns else 'Type'\n        if type_col not in df.columns:\n            return pd.DataFrame()\n\n        summary = df.groupby(type_col).agg({\n            'ElementId': 'count'\n        }).reset_index()\n        summary.columns = ['Element_Type', 'Count']\n        return summary.sort_values('Count', ascending=False)\n\n    def get_cells(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Get cell references (similar to blocks in DWG).\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        # Filter to cell elements\n        cells = df[df['ElementType'].isin([2, 35])]  # CELL_HEADER, SHARED_CELL\n\n        if cells.empty or 'CellName' not in cells.columns:\n            return pd.DataFrame(columns=['Cell_Name', 'Count'])\n\n        summary = cells.groupby('CellName').agg({\n            'ElementId': 'count'\n        }).reset_index()\n        summary.columns = ['Cell_Name', 'Count']\n        return summary.sort_values('Count', ascending=False)\n\n    def get_text_content(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Extract all text from DGN.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        # Filter to text elements\n        text_types = [7, 17]  # TEXT_NODE, TEXT\n        texts = df[df['ElementType'].isin(text_types)]\n\n        if 'TextContent' in texts.columns:\n            return texts[['ElementId', 'Level', 'TextContent']].copy()\n        return texts[['ElementId', 'Level']].copy()\n\n    def get_statistics(self, xlsx_file: str) -> Dict[str, Any]:\n        \"\"\"Get comprehensive DGN statistics.\"\"\"\n        df = self.read_elements(xlsx_file)\n\n        stats = {\n            'total_elements': len(df),\n            'levels_used': df['Level'].nunique() if 'Level' in df.columns else 0,\n            'element_types': df['ElementType'].nunique() if 'ElementType' in df.columns else 0\n        }\n\n        # Calculate extents\n        for coord in ['X', 'Y', 'Z']:\n            low_col = f'RangeLow{coord}'\n            high_col = f'RangeHigh{coord}'\n            if low_col in df.columns and high_col in df.columns:\n                stats[f'min_{coord.lower()}'] = df[low_col].min()\n                stats[f'max_{coord.lower()}'] = df[high_col].max()\n\n        return stats\n\n\nclass DGNAnalyzer:\n    \"\"\"Advanced DGN analysis for infrastructure projects.\"\"\"\n\n    def __init__(self, exporter: DGNExporter):\n        self.exporter = exporter\n\n    def analyze_infrastructure(self, dgn_file: str) -> Dict[str, Any]:\n        \"\"\"Analyze DGN for infrastructure elements.\"\"\"\n        xlsx = self.exporter.convert(dgn_file)\n        df = self.exporter.read_elements(str(xlsx))\n\n        analysis = {\n            'file': dgn_file,\n            'statistics': self.exporter.get_statistics(str(xlsx)),\n            'levels': self.exporter.get_levels(str(xlsx)).to_dict('records'),\n            'element_types': self.exporter.get_element_types(str(xlsx)).to_dict('records'),\n            'cells': self.exporter.get_cells(str(xlsx)).to_dict('records')\n        }\n\n        # Identify infrastructure-specific elements\n        if 'ElementType' in df.columns:\n            # Lines and shapes (often roads, boundaries)\n            lines = df[df['ElementType'].isin([3, 4, 6, 14])].shape[0]\n            analysis['linear_elements'] = lines\n\n            # Complex elements (often structures)\n            complex_elements = df[df['ElementType'].isin([12, 14, 18, 19])].shape[0]\n            analysis['complex_elements'] = complex_elements\n\n            # Annotation elements\n            annotations = df[df['ElementType'].isin([7, 17, 33])].shape[0]\n            analysis['annotations'] = annotations\n\n        return analysis\n\n    def compare_revisions(self, dgn1: str, dgn2: str) -> Dict[str, Any]:\n        \"\"\"Compare two DGN revisions.\"\"\"\n        xlsx1 = self.exporter.convert(dgn1)\n        xlsx2 = self.exporter.convert(dgn2)\n\n        df1 = self.exporter.read_elements(str(xlsx1))\n        df2 = self.exporter.read_elements(str(xlsx2))\n\n        levels1 = set(df1['Level'].unique()) if 'Level' in df1.columns else set()\n        levels2 = set(df2['Level'].unique()) if 'Level' in df2.columns else set()\n\n        return {\n            'revision1': dgn1,\n            'revision2': dgn2,\n            'element_count_diff': len(df2) - len(df1),\n            'levels_added': list(levels2 - levels1),\n            'levels_removed': list(levels1 - levels2),\n            'common_levels': len(levels1 & levels2)\n        }\n\n    def extract_coordinates(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Extract element coordinates for GIS integration.\"\"\"\n        df = self.exporter.read_elements(xlsx_file)\n\n        coord_cols = ['ElementId', 'Level', 'ElementType']\n        for col in ['RangeLowX', 'RangeLowY', 'RangeLowZ',\n                    'RangeHighX', 'RangeHighY', 'RangeHighZ',\n                    'CenterX', 'CenterY', 'CenterZ']:\n            if col in df.columns:\n                coord_cols.append(col)\n\n        return df[coord_cols].copy()\n\n\nclass DGNLevelManager:\n    \"\"\"Manage DGN level structures.\"\"\"\n\n    def __init__(self, exporter: DGNExporter):\n        self.exporter = exporter\n\n    def get_level_map(self, xlsx_file: str) -> Dict[int, str]:\n        \"\"\"Create level number to name mapping.\"\"\"\n        df = self.exporter.read_elements(xlsx_file)\n\n        if 'Level' not in df.columns:\n            return {}\n\n        # MicroStation levels are typically numbered 1-63 (V7) or unlimited (V8)\n        level_map = {}\n        for level in df['Level'].unique():\n            level_map[int(level)] = f\"Level_{level}\"\n\n        return level_map\n\n    def filter_by_levels(self, xlsx_file: str,\n                         levels: List[int]) -> pd.DataFrame:\n        \"\"\"Filter elements by level numbers.\"\"\"\n        df = self.exporter.read_elements(xlsx_file)\n        return df[df['Level'].isin(levels)]\n\n    def get_level_usage_report(self, xlsx_file: str) -> pd.DataFrame:\n        \"\"\"Generate level usage report.\"\"\"\n        df = self.exporter.read_elements(xlsx_file)\n\n        if 'Level' not in df.columns or 'ElementType' not in df.columns:\n            return pd.DataFrame()\n\n        # Cross-tabulate levels and element types\n        report = pd.crosstab(df['Level'], df['ElementType'], margins=True)\n        return report\n\n\n# Convenience functions\ndef convert_dgn_to_excel(dgn_file: str,\n                         exporter_path: str = \"DgnExporter.exe\") -> str:\n    \"\"\"Quick conversion of DGN to Excel.\"\"\"\n    exporter = DGNExporter(exporter_path)\n    output = exporter.convert(dgn_file)\n    return str(output)\n\n\ndef analyze_dgn(dgn_file: str,\n                exporter_path: str = \"DgnExporter.exe\") -> Dict[str, Any]:\n    \"\"\"Analyze DGN file and return summary.\"\"\"\n    exporter = DGNExporter(exporter_path)\n    analyzer = DGNAnalyzer(exporter)\n    return analyzer.analyze_infrastructure(dgn_file)\n\nOutput Structure\nExcel Sheets\nSheet\tContent\nElements\tAll DGN elements with properties\nLevels\tLevel definitions\nCells\tCell library\nElement Columns\nColumn\tType\tDescription\nElementId\tint\tUnique element ID\nElementType\tint\tType code (3=Line, 17=Text, etc.)\nLevel\tint\tLevel number\nColor\tint\tColor index\nWeight\tint\tLine weight\nStyle\tint\tLine style\nRangeLowX/Y/Z\tfloat\tBounding box minimum\nRangeHighX/Y/Z\tfloat\tBounding box maximum\nCellName\tstring\tCell name (for cell elements)\nTextContent\tstring\tText content (for text elements)\nQuick Start\n# Initialize exporter\nexporter = DGNExporter(\"C:/DDC/DgnExporter.exe\")\n\n# Convert DGN to Excel\nxlsx = exporter.convert(\"C:/Projects/Highway.dgn\")\nprint(f\"Output: {xlsx}\")\n\n# Read elements\ndf = exporter.read_elements(str(xlsx))\nprint(f\"Total elements: {len(df)}\")\n\n# Get level statistics\nlevels = exporter.get_levels(str(xlsx))\nprint(levels)\n\n# Get element types\ntypes = exporter.get_element_types(str(xlsx))\nprint(types)\n\nCommon Use Cases\n1. Infrastructure Analysis\nexporter = DGNExporter()\nanalyzer = DGNAnalyzer(exporter)\n\nanalysis = analyzer.analyze_infrastructure(\"highway.dgn\")\nprint(f\"Total elements: {analysis['statistics']['total_elements']}\")\nprint(f\"Linear elements: {analysis['linear_elements']}\")\nprint(f\"Annotations: {analysis['annotations']}\")\n\n2. Level Audit\nexporter = DGNExporter()\nxlsx = exporter.convert(\"bridge.dgn\")\nlevels = exporter.get_levels(str(xlsx))\n\n# Check for unused standard levels\nfor idx, row in levels.iterrows():\n    print(f\"Level {row['Level']}: {row['Element_Count']} elements\")\n\n3. GIS Integration\nanalyzer = DGNAnalyzer(exporter)\nxlsx = exporter.convert(\"utilities.dgn\")\ncoords = analyzer.extract_coordinates(str(xlsx))\n\n# Export for GIS\ncoords.to_csv(\"coordinates.csv\", index=False)\n\n4. Revision Comparison\nanalyzer = DGNAnalyzer(exporter)\ndiff = analyzer.compare_revisions(\"rev1.dgn\", \"rev2.dgn\")\nprint(f\"Elements changed: {diff['element_count_diff']}\")\n\nIntegration with DDC Pipeline\n# Infrastructure pipeline: DGN → Excel → Analysis\nfrom dgn_exporter import DGNExporter, DGNAnalyzer\n\n# 1. Convert DGN\nexporter = DGNExporter(\"C:/DDC/DgnExporter.exe\")\nxlsx = exporter.convert(\"highway_project.dgn\")\n\n# 2. Analyze structure\nstats = exporter.get_statistics(str(xlsx))\nprint(f\"Elements: {stats['total_elements']}\")\nprint(f\"Levels: {stats['levels_used']}\")\n\n# 3. Extract for GIS\nanalyzer = DGNAnalyzer(exporter)\ncoords = analyzer.extract_coordinates(str(xlsx))\ncoords.to_csv(\"for_gis.csv\", index=False)\n\nBest Practices\nCheck version - V7 and V8 have different capabilities\nReference files - Process all reference files separately\nLevel mapping - Document level standards for your organization\nCoordinate systems - Verify units and coordinate systems\nCell libraries - Export cells separately if needed\nResources\nGitHub: cad2data Pipeline\nDDC Book: Chapter 2.4 - CAD Data Extraction\nMicroStation: Infrastructure-focused CAD software"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/datadrivenconstruction/dgn-to-excel",
    "publisherUrl": "https://clawhub.ai/datadrivenconstruction/dgn-to-excel",
    "owner": "datadrivenconstruction",
    "version": "2.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/dgn-to-excel",
    "downloadUrl": "https://openagent3.xyz/downloads/dgn-to-excel",
    "agentUrl": "https://openagent3.xyz/skills/dgn-to-excel/agent",
    "manifestUrl": "https://openagent3.xyz/skills/dgn-to-excel/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/dgn-to-excel/agent.md"
  }
}