XMLCoder icon indicating copy to clipboard operation
XMLCoder copied to clipboard

How do I handle encoding and decoding an element and attribute with the same name but different types?

Open EricSites opened this issue 5 years ago • 3 comments

How do I handle encoding and decoding an element and attribute with the same name but different types?

<!ELEMENT barline (segno?, coda?)>
<!ATTLIST barline
    segno CDATA #IMPLIED
    coda CDATA #IMPLIED
>
<!ELEMENT segno EMPTY>
<!ATTLIST segno
    %optional-unique-id;
    %smufl;
>
<!ELEMENT coda EMPTY>
<!ATTLIST coda
    %optional-unique-id;
    %smufl;
>
<!ENTITY % smufl
	"smufl %smufl-glyph-name; #IMPLIED">
<!ENTITY % optional-unique-id
	"id ID #IMPLIED">
<!ENTITY % smufl-glyph-name "NMTOKEN">

Example XML

<barline coda="name-1">
    <coda id="1" smufl="coda-char" />
</barline>

Here is what I have done so far, but doesn't work:

struct Segno: Codable, Equatable, DynamicNodeDecoding, DynamicNodeEncoding {
    var id: String? // %optional-unique-id
    var smufl: String? // %smufl

    enum CodingKeys: String, CodingKey {
            case id
            case smufl
    }
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
            switch key { default: return .attribute }
    }
	static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
            switch key { default: return .attribute }
    }
}

struct Coda: Codable, Equatable, DynamicNodeDecoding, DynamicNodeEncoding {
    var id: String? // %optional-unique-id
    var smufl: String? // %smufl

    enum CodingKeys: String, CodingKey {
            case id
            case smufl
    }
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
            switch key { default: return .attribute }
    }
	static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
            switch key { default: return .attribute }
    }
}

struct Barline: Codable, Equatable, DynamicNodeDecoding, DynamicNodeEncoding {
    var segnoE: Segno?
    var codaE: Coda?
    var segno: String? // CDATA #IMPLIED
    var coda: String? // CDATA #IMPLIED

    enum CodingKeys: String, CodingKey {
        case segno
        case coda
    }
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
            switch key {
            	case CodingKeys.coda: return .attribute
            	case CodingKeys.segno: return .attribute
            	default: return .element
            }
	}
	static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
            switch key {
            	case CodingKeys.coda: return .attribute
            	case CodingKeys.segno: return .attribute
            	default: return .element
            }
	}
}

EricSites avatar Jun 11 '20 00:06 EricSites

For Codable, one property is with one key. In you sample, coda in attribute and element shares the same key. Two properties are with one key. That is a conflict. I don't think there is a way for this other than solving the conflict first.

owenzhao avatar Jun 12 '20 00:06 owenzhao

For Codable, one property is with one key. In you sample, coda in attribute and element shares the same key. Two properties are with one key. That is a conflict. I don't think there is a way for this other than solving the conflict first.

This is a valid XML schema that I can't change. I need to parse it.

EricSites avatar Jun 12 '20 01:06 EricSites

For Codable, one property is with one key. In you sample, coda in attribute and element shares the same key. Two properties are with one key. That is a conflict. I don't think there is a way for this other than solving the conflict first.

This is a valid XML schema that I can't change. I need to parse it.

You don't need to change the xml file. Just add another layer.

  1. read the xml as String.
  2. replacing all "<coda" to something like "<codaE"
  3. convert the String to Data.
  4. use XMLCoder decode the data.

owenzhao avatar Jun 12 '20 07:06 owenzhao