CoreOffice / XMLCoder

Easy XML parsing using Codable protocols in Swift
https://coreoffice.github.io/XMLCoder/
MIT License
801 stars 112 forks source link

XML with autoclosed tags #116

Closed mackmilan closed 5 years ago

mackmilan commented 5 years ago

I have the following xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14490.99" systemVersion="18F132" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
   <entity name="Pessoa" representedClassName="Pessoa" syncable="YES" codeGenerationType="class">
      <attribute name="id" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
   </entity>
</model>

and the structs:

struct Model: Codable, Equatable, DynamicNodeEncoding {

    let type: String
    let documentVersion: String
    let lastSavedToolsVersion: String
    let systemVersion: String
    let minimumToolsVersion: String
    let sourceLanguage: String
    let userDefinedModelVersionIdentifier: String
    let entities: [Entity]

    enum CodingKeys: String, CodingKey {
        case type
        case documentVersion
        case lastSavedToolsVersion
        case systemVersion
        case minimumToolsVersion
        case sourceLanguage
        case userDefinedModelVersionIdentifier
        case entities = "entity"
    }

    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        switch key {
        case Model.CodingKeys.type: return .both
        case Model.CodingKeys.documentVersion: return .both
        case Model.CodingKeys.lastSavedToolsVersion: return .both
        case Model.CodingKeys.systemVersion: return .both
        case Model.CodingKeys.minimumToolsVersion: return .both
        case Model.CodingKeys.sourceLanguage: return .both
        case Model.CodingKeys.userDefinedModelVersionIdentifier: return .both
        default: return .element
        }
    }
}

struct Entity: Codable, Equatable, DynamicNodeEncoding {

    let name: String
    let representedClassName: String
    let syncable: String
    let codeGenerationType: String
    let attributes: [Attribute]

    enum CodingKeys: String, CodingKey {
        case name
        case representedClassName
        case syncable
        case codeGenerationType
        case attributes = "attribute"
    }

    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        switch key {
        case Entity.CodingKeys.name: return .both
        case Entity.CodingKeys.representedClassName: return .both
        case Entity.CodingKeys.syncable: return .both
        case Entity.CodingKeys.codeGenerationType: return .both
        default: return .element
        }
    }

}

struct Attribute: Codable, Equatable, DynamicNodeEncoding {

    let name: String
    let optional: String
    let attributeType: String
    let defaultValueString: String
    let userScalarValueType: String
    let syncable: String

    enum CodingKeys: String, CodingKey {
        case name
        case optional
        case attributeType
        case defaultValueString
        case userScalarValueType
        case syncable
    }

    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        switch key {
        case Attribute.CodingKeys.name: return .both
        case Attribute.CodingKeys.optional: return .both
        case Attribute.CodingKeys.attributeType: return .both
        case Attribute.CodingKeys.defaultValueString: return .both
        case Attribute.CodingKeys.userScalarValueType: return .both
        case Attribute.CodingKeys.syncable: return .both
        default:
            return .element
        }
    }

}

when I ran the decode, I get the error:

Fatal error: Unrecognized top-level element of type: NullBox: file

and it's related to the attributes array in Entity, could you help me please?

MaxDesiatov commented 5 years ago

Hi @mackmilan, sorry for the delayed reply. Thank you for submitting the XML snippet and the model files. Unfortunately, I don't think that the supplied XML is exactly the same as the one that reproduced your error. There's neither file element nor file attribute present anywhere in that XML. When I pasted the XML and the model types in my tests, I got a different error caused by one of the attributes being absent. The corresponding property was not optional, so changing it to let userScalarValueType: String? with the optional String? fixed the error for these snippets.

I don't think that this is related to autoclosed tags. Would you be able to attach the complete snippet that causes the issue for you?

mackmilan commented 5 years ago

@MaxDesiatov, you are absolutely right, is not that xml, in fact, I can't reproduce the error anymore, I've changed the userScalarValueType attribute to optional, it works very well. Thank you for your time.