schwitters/openswx
GitHub: schwitters/openswx
跨平台 C++20 工具包,读取 SolidWorks 文件并构建 BOM,提供本地解析库与 Web 查询服务。
Stars: 0 | Forks: 0
# openswx
一个跨平台的工具包,用于读取 SolidWorks® 文件(`.SLDPRT`、`.SLDASM`、`.SLDDRW`),无需安装 SolidWorks、COM 或任何仅 Windows 的依赖。
## 概述
该仓库包含三个独立的组件:
```
openswx/
├── libopenswx/ Pure C++20 library — parses SolidWorks files
├── libopenbom/ Pure C++20 library — builds hierarchical BOMs (built on libopenswx)
└── asmbox/ HTTP server + CLI tool — built on top of both libraries
```
### libopenswx
一个零依赖的 C++20 静态库,可读取两种 SolidWorks 文件格式:
| 格式 | 版本 | 检测 |
|--------|----------|-----------|
| 现代分块格式 | SW 2015 及更新版本 | 字节扫描标记 `14 00 06 00 08 00` |
| OLE2 复合文档 | SW 2014 及更早版本 | 魔术数 `D0 CF 11 E0 A1 B1 1A E1` |
每个文档提取的数据:
- **文档类型**(零件 / 装配体 / 工程图)
- **模型版本** 编号
- **全局自定义属性**(`docProps/custom.xml`)
- **文档预览** PNG 缩略图
- 每个 **配置**:名称、自定义属性、质量属性(重心、体积、表面积、质量、惯性张量)、预览 PNG、切割清单项(焊件)、装配体组件引用
- 每个 **图纸页**:名称、预览 PNG、视图引用
### libopenbom
一个 C++20 静态库,用于从 SolidWorks 文件构建层次化、递归的物料清单(BOM)。它将 Windows 组件路径解析为主机文件系统路径,聚合相同实例,并将结果序列化为 JSON。
关键类型:
| 类型 | 描述 |
|------|-------------|
| `BomTransformer` | 入口点 — 调用 `Build(path)` 生成 `Bom` |
| `BomTransformerConfig` | 控制配置选择、过滤、递归深度、路径解析 |
| `PathResolverConfig` | 通过前缀替换和目录搜索将 Windows 路径映射到主机路径 |
| `BomItem` | BOM 树中的一行(名称、数量、属性、子项) |
| `Bom` | 根 `BomItem` 加上累积的警告 |
| `JsonWriter` | 将 `Bom` 序列化为 JSON 字符串或文件 |
### asmbox
一个 Linux HTTP 服务器,允许你上传 SolidWorks 文件的 ZIP 归档并在 Web UI 中浏览提取的元数据、BOM 树和自定义属性。 它还附带 `swx_dump`,一个命令行工具,用于打印任意单个 SolidWorks 文件的 JSON 表示。
## 先决条件
| 软件包 | 最低版本 | 用途 |
|---------|----------------|---------|
| CMake | 3.20 | 构建系统 |
| GCC 或 Clang | C++20 兼容(GCC 12+) | 编译器 |
| zlib (`libz-dev`) | 任意 | libopenswx 中的原始 Deflate 解压缩 |
| pugixml (`libpugixml-dev`) | 1.11+ | libopenswx 中的 XML 解析 |
| nlohmann/json (`nlohmann-json3-dev`) | 3.x | asmbox 中的 JSON 序列化 |
| SQLite3 (`libsqlite3-dev`) | 3.x | asmbox 中的结果缓存和 BOM 持久化 |
| libzip (`libzip-dev`) | 1.x | asmbox 中的 ZIP 上传处理 |
以下内容由 CMake 的 `FetchContent` 在配置时自动获取:
- **Crow** v1.2.0 — HTTP 服务器框架
- **plog** v1.1.10 — 日志记录
- **googletest** v1.15.2 — 单元测试
在 Debian/Ubuntu 上,使用以下命令安装系统软件包:
```
sudo apt install cmake build-essential \
libz-dev libpugixml-dev nlohmann-json3-dev \
libsqlite3-dev libzip-dev
```
## 构建
```
cd openswx
# 配置(自动下载 Crow、plog、googletest)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
# 构建所有内容
cmake --build build -j$(nproc)
```
这将在 `build/asmbox/` 中生成三个二进制文件:
| 二进制文件 | 描述 |
|--------|-------------|
| `asmbox` | HTTP 服务器(默认端口 8087) |
| `swx_dump` | CLI 工具 — 打印 JSON 到标准输出 |
| `asmbox_tests` | 单元测试套件 |
运行测试:
```
./build/asmbox/asmbox_tests
```
## 教程
### 1. 使用 `swx_dump` 检查单个文件
```
./build/asmbox/swx_dump /path/to/part.SLDPRT | python3 -m json.tool
```
示例输出(截断):
```
{
"doc_type": 1,
"version": 17000,
"global_properties": {
"Desc1": "Winkelstecker",
"Material": "Messing"
},
"configurations": [
{
"name": "Standard",
"properties": { "Configuration": "Standard" },
"mass_properties": {
"mass": 0.0251,
"volume": 2.5e-06,
"surface_area": 0.00654,
"center_of_gravity": { "x": -0.003, "y": 0.0, "z": 0.013 }
}
}
]
}
```
`doc_type` 值:`1` = 零件,`2` = 装配体,`3` = 工程图。
所有质量/几何值均采用 SI 单位(kg、m、m²、m³)。
### 2. 运行 asmbox Web 服务器
```
./build/asmbox/asmbox
```
服务器在 `http://0.0.0.0:8087` 启动。
在浏览器中打开 `http://localhost:8087` 访问上传界面。
**上传 ZIP 归档**:包含一个或多个 SolidWorks 文件。服务器将:
1. 解压归档到 `ASMBOX_DATA_DIR//`
2. 扫描 `.SLDPRT`、`.SLDASM` 和 `.SLDDRW` 文件
3. 立即分析每个文件并将结果缓存在 SQLite 中
4. 返回找到的文件列表(JSON 格式)
**浏览工作区**:在侧边栏中浏览工作区,点击任意文件查看其解析的文档数据和属性。
**查看 BOM**:在装配体和工程图文件的“物料清单”标签页中查看。 BOM 会通过解析工作区目录中的组件路径递归构建。
**配置属性**:按工作区配置可见属性,并分配语义角色(`part_number`、`description`、`material`、`revision`)。被指定为 `part_number` 的属性在持久化 BOM 时使用。
**配置文件**:允许你定义与工作区无关的可重用映射和转换规则(它们在删除工作区或重启服务器后仍然保留):
- **映射**:将 SolidWorks 自定义属性名称映射到输出中的结构化字段(Part、BomItem 或 Bom Thrift 实体)。
- **规则**:实时转换 BOM 树:
- `kaufgruppe` — 保留匹配项但移除其子项。
- `non_bom` — 完全排除匹配项。
- `phantom` — 排除匹配项并将其子项提升一级。
通过在 URL 后添加 `?profile=` 来应用配置文件到 BOM 请求。
**可调整面板**:在“详细信息”视图、“物料清单”视图和侧边栏中拖动分隔条来调整面板大小。宽度会保存在 `localStorage` 中。
### 3. 通过环境变量配置
所有设置均使用 `ASMBOX_` 前缀,并具有合理的默认值:
| 变量 | 默认值 | 描述 |
|----------|---------|-------------|
| `ASMBOX_BIND_ADDR` | `0.0.0.0` | 绑定的 IP 地址 |
| `ASMBOX_PORT` | `8087` | TCP 端口 |
| `ASMBOX_DATA_DIR` | `$TMPDIR/sw_portal` | 工作区和 SQLite 数据库的根目录 |
| `ASMBOX_TEMPLATE_DIR` | `templates` | 包含 Crow HTML 模板的目录 |
SQLite 数据库(`global.sqlite`)存储在 `ASMBOX_DATA_DIR` 中,并在服务器重启后保持持久化。 架构使用 `CREATE TABLE IF NOT EXISTS` 创建,因此重启服务器不会清除缓存的数据或配置文件。
示例 — 在非默认端口上运行,仅绑定到本地主机,并使用持久化数据目录:
```
ASMBOX_PORT=9090 \
ASMBOX_BIND_ADDR=127.0.0.1 \
ASMBOX_DATA_DIR=/var/lib/asmbox \
ASMBOX_TEMPLATE_DIR=/usr/share/asmbox/templates \
./build/asmbox/asmbox
```
### 4. 在你自己的项目中使用 libopenswx
将 libopenswx 添加到子目录并链接:
```
add_subdirectory(path/to/openswx/libopenswx)
target_link_libraries(my_target PRIVATE openswx)
```
最小用法:
```
#include "openswx/document.h"
auto result = openswx::SwxDocument::Open("part.SLDPRT");
if (!result.ok()) {
std::cerr << result.error() << "\n";
return 1;
}
const openswx::Document& doc = result.value().doc();
for (const auto& cfg : doc.configurations) {
std::cout << "Config: " << cfg.name << "\n";
if (cfg.mass_properties) {
std::cout << " Mass: " << cfg.mass_properties->mass << " kg\n";
}
for (const auto& [key, val] : cfg.properties) {
std::cout << " " << key << " = " << val << "\n";
}
}
```
### 5. 在你自己的项目中使用 libopenbom
同时添加两个库并链接:
```
add_subdirectory(path/to/openswx/libopenswx)
add_subdirectory(path/to/openswx/libopenbom)
target_link_libraries(my_target PRIVATE openbom openswx)
```
最小用法:
```
#include "openbom/transformer.h"
#include "openbom/json_writer.h"
openbom::BomTransformerConfig cfg;
// Map Windows component paths to the host filesystem.
cfg.path_resolver.substitutions.push_back(
{"C:\\Engineering\\Parts\\", "/mnt/nas/parts/"});
// Or simply search a local directory by filename.
cfg.path_resolver.search_dirs.push_back("/data/parts");
cfg.path_resolver.recursive_search = true;
cfg.path_resolver.case_insensitive = true;
openbom::BomTransformer transformer(cfg);
auto result = transformer.Build("/data/top_asm.SLDASM");
if (!result.ok()) {
std::cerr << result.error() << "\n";
return 1;
}
const openbom::Bom& bom = result.value();
for (const auto& w : bom.warnings)
std::cerr << "Warning: " << w << "\n";
openbom::JsonWriter writer;
writer.WriteToFile(bom, "bom.json");
```
`BomTransformerConfig` 选项:
| 字段 | 默认值 | 描述 |
|-------|---------|-------------|
| `configuration_name` | `"" | SolidWorks 配置名称;空值表示使用第一个 |
| `include_suppressed` | `false` | 包含被抑制的装配体组件 |
| `include_hidden` | `false` | 包含隐藏的装配体组件 |
| `include_exclude_from_bom` | `false` | 包含标记为“排除 BOM”的组件 |
| `expand_cut_lists` | `true` | 将焊件切割清单项作为子项添加 |
| `max_depth` | `0` | 最大递归深度(0 = 无限制) |
| `path_resolver` | — | 用于 Windows 到主机路径映射的 `PathResolverConfig` |
| `item_callback` | `nullptr` | 每个 `BomItem` 的可选后处理回调 |
## REST API 参考
| 方法 | 路径 | 描述 |
|--------|------|-------------|
| `GET` | `/` | Web UI(`index.html`) |
| `GET` | `/api/workspaces` | 以 JSON 列出所有工作区 |
| `DELETE` | `/api/workspaces/` | 删除工作区及其文件 |
| `POST` | `/upload` | 上传包含 `file` 字段(ZIP)的 `multipart/form-data` 请求 |
| `GET` | `/api/doc//` | 单个文件的解析文档 JSON(缓存在 SQLite 中) |
| `GET` | `/api/workspaces//props` | 属性名称及工作区配置 |
| `POST` | `/api/workspaces//props` | 保存属性配置(可见性、角色) |
| `GET` | `/api/profiles` | 列出所有配置文件 |
| `POST` | `/api/profiles` | 创建配置文件 `{name, description}` |
| `GET` | `/api/profiles/` | 完整配置文件(名称、描述、映射、规则) |
| `PUT` | `/api/profiles/` | 保存完整配置文件(更新映射和规则) |
| `DELETE` | `/api/profiles/` | 删除配置文件 |
| `GET` | `/api/bom//` | 构建 BOM;可选通过 `?profile=` 应用配置文件 |
`` 是工作区内相对文件路径的 Base64url 编码。
## 架构说明
```
SolidWorks file
│
▼
libopenswx::ParseFile()
├─ IsOle2() → ParseOle2Format() (OLE2 FAT/directory/sector chain)
└─ ParseModernFormat() (marker scan + ROL-decoded names + raw deflate)
│
▼
StreamMap (flat map: stream-path → decompressed bytes)
│
├─ ParsePropertyXml() docProps/custom.xml, Config-N-Properties.xml
├─ ParseMassProperties() docProps/ISolidWorksInformation.xml
├─ ParseCutlistXml() docProps/Config-N-Cutlist-Properties.xml
├─ ParseComponents() swXmlContents/COMPINSTANCETREE
├─ ParseSheetNames() SheetPreviews/SheetNames
└─ ExtractPng() PreviewPNG / Config-N-PreviewPNG
libopenbom::BomTransformer::Build()
│
├─ Detect file type (part / assembly / drawing)
├─ Select active configuration
├─ Recursively expand assembly components
│ ├─ PathResolver: Windows path → host path
│ │ ├─ Prefix substitution rules
│ │ └─ Directory search (shallow + optional recursive)
│ └─ Aggregate identical instances (quantity > 1)
└─ Return Bom { root: BomItem, warnings: [...] }
asmbox (server.cc)
│
├─ POST /upload → unzip, scan, eager-analyze all SWX files
├─ GET /api/doc → load or analyze + cache in SQLite
├─ GET /api/bom → BomTransformer::Build() + ApplyBomRules(profile)
│ + SaveBom() to SQLite (surrogate-key schema)
├─ GET|POST /api/workspaces//props → property config CRUD
└─ /api/profiles[/] → profile CRUD (workspace-independent)
SQLite schema (global.sqlite, persistent)
├─ workspaces, files, documents, properties
├─ boms, bom_items (surrogate-key BOM persistence)
├─ property_configs (per-workspace property visibility + roles)
└─ profiles, profile_mappings, profile_rules (workspace-independent)
```
两种文件格式均会自动检测。库在读取文件时不会写入磁盘,也不会执行任何系统调用。
标签:Bill of Materials, BOM, C++, C++20, HTTP服务器, JSON序列化, SolidWorks, Web服务, 云资产清单, 切割清单, 开源, 技术文档, 数据提取, 数据擦除, 文件解析, 网络测绘, 自定义属性, 装配引用, 质量属性, 路径映射, 逆向工程, 递归构建, 配置文件驱动, 零依赖, 静态库, 预览缩略图