Skip to content

Commit f4cc160

Browse files
committed
Add support for custom attributes for item and remove built-in support for Prusa's printable attribute
1 parent c28b923 commit f4cc160

File tree

4 files changed

+25
-9
lines changed

4 files changed

+25
-9
lines changed

Sources/ThreeMF/Model/Item.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,40 @@ public struct Item: Sendable, XMLElementCodable {
55
public var objectID: ResourceID
66
public var transform: Matrix3D?
77
public var partNumber: String?
8-
public var printable: Bool? // Prusa extension
98
public var metadata: [Metadata]
9+
public var customAttributes: [ExpandedName: String]
1010

11-
public init(objectID: ResourceID, transform: Matrix3D? = nil, partNumber: String? = nil, metadata: [Metadata] = [], printable: Bool? = nil) {
11+
public init(
12+
objectID: ResourceID,
13+
transform: Matrix3D? = nil,
14+
partNumber: String? = nil,
15+
metadata: [Metadata] = [],
16+
customAttributes: [ExpandedName: String] = [:]
17+
) {
1218
self.objectID = objectID
1319
self.transform = transform
1420
self.partNumber = partNumber
1521
self.metadata = metadata
16-
self.printable = printable
22+
self.customAttributes = customAttributes
1723
}
1824

1925
public func encode(to element: Node) {
2026
element.setValue(objectID, forAttribute: .objectID)
2127
element.setValue(transform, forAttribute: .transform)
2228
element.setValue(partNumber, forAttribute: .partNumber)
23-
element.setValue(printable, forAttribute: .printable)
2429
element.encode(metadata, elementName: Core.metadata, containedIn: Core.metadataGroup)
30+
for (name, value) in customAttributes {
31+
element.setValue(value, forAttribute: name)
32+
}
2533
}
2634

2735
public init(from element: Node) throws {
2836
objectID = try element.value(forAttribute: .objectID)
2937
transform = try element.value(forAttribute: .transform)
3038
partNumber = try element.value(forAttribute: .partNumber)
31-
printable = try element.value(forAttribute: .printable)
3239
metadata = try element.decode(elementName: Core.metadata, containedIn: Core.metadataGroup)
40+
41+
let knownAttributes: Set<ExpandedName> = [.objectID, .transform, .partNumber, Core.metadataGroup]
42+
customAttributes = element.namespacedAttributes.filter { !knownAttributes.contains($0.key) }
3343
}
3444
}

Sources/ThreeMF/Model/Model.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public struct Model: Sendable, XMLElementCodable {
88

99
public var requiredExtensions: Set<Namespace>
1010
public var recommendedExtensions: Set<Namespace>
11+
public var customNamespaces: [String: String]
1112

1213
public var metadata: [Metadata]
1314
public var resources: ResourceContainer
@@ -19,6 +20,7 @@ public struct Model: Sendable, XMLElementCodable {
1920
languageCode: String? = nil,
2021
requiredExtensions: Set<Namespace> = [],
2122
recommendedExtensions: Set<Namespace> = [],
23+
customNamespaces: [String: String] = [:], // Prefix: URI
2224
metadata: [Metadata] = [],
2325
resources: [any Resource] = [],
2426
buildItems: [Item] = []
@@ -28,6 +30,7 @@ public struct Model: Sendable, XMLElementCodable {
2830
self.languageCode = languageCode
2931
self.requiredExtensions = requiredExtensions
3032
self.recommendedExtensions = recommendedExtensions
33+
self.customNamespaces = customNamespaces
3134

3235
self.metadata = metadata
3336
self.resources = ResourceContainer(resources: resources)
@@ -50,7 +53,6 @@ public struct Model: Sendable, XMLElementCodable {
5053
xmlLanguageCode = try element.value(forAttribute: XML.lang)
5154
languageCode = try element.value(forAttribute: .language)
5255

53-
5456
if let requiredExtensionPrefixes: [String] = try element.value(forAttribute: .requiredExtensions) {
5557
requiredExtensions = Namespace.namespaces(forPrefixes: requiredExtensionPrefixes, in: element)
5658
} else {
@@ -63,6 +65,9 @@ public struct Model: Sendable, XMLElementCodable {
6365
recommendedExtensions = []
6466
}
6567

68+
let knownNamespaces = Set(Namespace.known.map(\.uri))
69+
customNamespaces = element.declaredNamespaces.filter { $0 != nil && knownNamespaces.contains($1) } as! [String: String]
70+
6671
metadata = try element.decode(elementName: Core.metadata)
6772
resources = try element.decode(elementName: Core.resources)
6873
buildItems = try element.decode(elementName: Core.item, containedIn: Core.build)

Sources/ThreeMF/Namespace/Attributes.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ extension AttributeName where Self == ExpandedName {
3939
static var p2: Self { attribute("p2") }
4040
static var p3: Self { attribute("p3") }
4141

42-
// This is a Prusa extension. It should live in its own namespace, but alas, it does not
43-
static var printable: Self { attribute("printable") }
44-
4542
// MARK: - Materials
4643
static var displayPropertiesID: Self { attribute("displaypropertiesid") }
4744
static var values: Self { attribute("values") }

Sources/ThreeMF/Package/PackageWriter.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ internal extension PackageWriter {
7777
func xmlDocument() -> Document {
7878
let modelDocument = Document(model, elementName: Core.model)
7979

80+
for (prefix, uri) in model.customNamespaces {
81+
modelDocument.documentElement?.declareNamespace(uri, forPrefix: prefix)
82+
}
83+
8084
for namespaceName in modelDocument.undeclaredNamespaceNames {
8185
guard let namespace = Namespace.knownNamespace(for: namespaceName) else {
8286
assertionFailure("Unknown namespace \(namespaceName)")

0 commit comments

Comments
 (0)