Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can inheritance be implemented? #159

Closed
monibu91 opened this issue Feb 21, 2020 · 4 comments
Closed

Can inheritance be implemented? #159

monibu91 opened this issue Feb 21, 2020 · 4 comments

Comments

@monibu91
Copy link

monibu91 commented Feb 21, 2020

I have this xml:

<my:page xmlns:my="http://schemas.myxml" id="a4ccae57-78fd-4232-aaff-67dd1c7f6d31">
	<my:group id="group-1" x="14%" y="24%" width="auto" height="auto" padding-left="5%" padding-right="5%" padding-top="2dp" padding-bottom="2dp" layout="absolute" grid-columns-count="2" justify-content="start-left">
	    <my:text id="text-1" x="5dp" y="6dp" width="auto" height="5dp" padding-left="10%" padding-right="5%" padding-top="5dp" padding-bottom="10dp" transform="matrix(a, b, c, d, tx, ty)" text-align="left" text-mode="single-line" horizontal-align="left" vertical-align="top" line-height="1.5" font-size="1.5" font-family="Times New Roman"></my:text>		   
	    <my:image id="img-1" x="15dp" y="16dp" width="adjust-to-min" height="15%" padding-left="20dp" padding-right="15dp" padding-top="15%" padding-bottom="20%" transform="matrix(a, b, c, d, tx, ty)" part-id="test-img" scale-type="fill" ></my:image>	
        <my:diagram id="diagram-1" x="25%" y="26%" width="adjust-to-max" height="25%" padding-left="20dp" padding-right="35%" padding-top="45dp" padding-bottom="55%" transform="matrix(a, b, c, d, tx, ty)" part-id="test-ink"></my:diagram>			
		<my:embed id="5" x="25%" y="26%" width="adjust-to-max" height="25%" padding-left="20dp" padding-right="35%" padding-top="45dp" padding-bottom="55%" transform="matrix(a, b, c, d, tx, ty)" part-id="test-diagram"></my:embed>			
		<my:group id="group-2" x="24%" y="34%" width="inf" height="inf" padding-left="15%" padding-right="15%" padding-top="5dp" padding-bottom="5dp" layout="flex" grid-columns-count="5" justify-content="distribute-evenly">			
		   <my:image id="img-2" x="15dp" y="16dp" width="adjust-to-min" height="15%" padding-left="20dp" padding-right="15dp" padding-top="15%" padding-bottom="20%" transform="matrix(a, b, c, d, tx, ty)" scale-type="fill" part-id="bd738193-46b2-401f-ad3c-998a9d28bd9e"></my:image>			   
		   <my:diagram id="diagram-2" x="25%" y="26%" width="adjust-to-max" height="25%" padding-left="20dp" padding-right="35%" padding-top="45dp" padding-bottom="55%" transform="matrix(a, b, c, d, tx, ty)" part-id="e0fbdab4-f2e7-4e2e-9126-76f94c025061"></my:diagram>			
		 </my:group>
	</my:group>
</my:page>

Which represents content on a page. The page has its properties and one group which is the root node of a tree structure. The nodes of the tree are "blocks". A block is like abstract class because there are no elements in the xml that are "block", but "group" , " text", "image", "diagram" and "embed" are blocks ( they have all the properties a block has (id, x, y, width, height, padding-left, padding-right, padding-top, padding-bottom). So my problem is that i don't find a way to express that group is an array of things that are some children of "block" structure. I have to encode and decode the xml.
Here is what i did so far:

import Foundation
import XMLCoder


protocol BlockModel: Codable {
    var id : String { get }
    
    //properties
    var x : String? { get set }
    var y : String? { get set }
    
    var width : String? { get set }
    var height : String? { get set }

    var paddingLeft : String? { get set }
    var paddingRight : String? { get set }
    var paddingTop : String? { get set }
    var paddingBottom : String? { get set }
}



struct GroupModel : BlockModel, Codable, DynamicNodeDecoding, DynamicNodeEncoding  {
//    var blocks : [BlockModel] = []
    
    var id : String

    //properties
    var x : String?
    var y : String?

    var width : String?
    var height : String?

    var paddingLeft : String?
    var paddingRight : String?
    var paddingTop : String?
    var paddingBottom : String?
    
    var layout: String
    var gridColumnsCount: String
    var justifyContent: String

    enum CodingKeys: String, CodingKey {
        case id,x,y,width, height
        
        case paddingLeft = "padding-left"
        case paddingRight = "padding-right"
        case paddingTop = "padding-top"
        case paddingBottom = "padding-bottom"
        
        case gridColumnsCount = "grid-columns-count"
        case justifyContent = "justify-content"
        
//        case blocks = "my:*"

    }
    
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
//        switch key {
//        case CodingKeys.blocks:
//            return .element
//        default:
            return .attribute
//        }
    }
    
    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
//        switch key {
//        case CodingKeys.blocks:
//            return .element
//        default:
            return .attribute
//        }
    }

}


struct TextModel : BlockModel, Codable, DynamicNodeDecoding, DynamicNodeEncoding  {
    var id : String

    //properties
    var x : String?
    var y : String?

    var width : String?
    var height : String?

    var paddingLeft : String?
    var paddingRight : String?
    var paddingTop : String?
    var paddingBottom : String?
    
    //text specific
    var textAlign: String
    var textMode: String
    var horizontalAlign: String
    var verticalAlign : String
    var lineHeight : String
    var fontSize : String
    var fontFamily : String

    enum CodingKeys: String, CodingKey {
        case id,x,y,width, height

        case paddingLeft = "padding-left"
        case paddingRight = "padding-right"
        case paddingTop = "padding-top"
        case paddingBottom = "padding-bottom"
        
        case textAlign = "text-align"
        case textMode = "text-mode"
        case horizontalAlign = "horizontal-align"
        case verticalAlign = "vertical-align"
        case lineHeight = "line-height"
        case fontSize = "font-size"
        case fontFamily = "font-family"

    }
    
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
        return .attribute
    }
    
    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        return .attribute
    }

}

struct ImageModel : BlockModel, Codable, DynamicNodeDecoding, DynamicNodeEncoding  {
    var id : String

    //properties
    var x : String?
    var y : String?

    var width : String?
    var height : String?

    var paddingLeft : String?
    var paddingRight : String?
    var paddingTop : String?
    var paddingBottom : String?
    
    var partId: String
    var scaleType: String

    enum CodingKeys: String, CodingKey {
        case id,x,y,width, height

        case paddingLeft = "padding-left"
        case paddingRight = "padding-right"
        case paddingTop = "padding-top"
        case paddingBottom = "padding-bottom"
        
        case partId = "r:part-id"
        case scaleType = "scale-type"

    }
    
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
        return .attribute
    }
    
    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        return .attribute
    }

}

struct DiagramModel : BlockModel, Codable, DynamicNodeDecoding, DynamicNodeEncoding  {
    var id : String

    //properties
    var x : String?
    var y : String?

    var width : String?
    var height : String?

    var paddingLeft : String?
    var paddingRight : String?
    var paddingTop : String?
    var paddingBottom : String?
    
    var partId: String

    enum CodingKeys: String, CodingKey {
        case id,x,y,width, height

        case paddingLeft = "padding-left"
        case paddingRight = "padding-right"
        case paddingTop = "padding-top"
        case paddingBottom = "padding-bottom"
        
        case partId = "r:part-id"
    }
    
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
        return .attribute
    }
    
    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        return .attribute
    }

}

struct EmbedModel : BlockModel, Codable, DynamicNodeDecoding, DynamicNodeEncoding  {
    var id : String

    //properties
    var x : String?
    var y : String?

    var width : String?
    var height : String?

    var paddingLeft : String?
    var paddingRight : String?
    var paddingTop : String?
    var paddingBottom : String?
    
    var partId: String

    enum CodingKeys: String, CodingKey {
        case id,x,y,width, height

        case paddingLeft = "padding-left"
        case paddingRight = "padding-right"
        case paddingTop = "padding-top"
        case paddingBottom = "padding-bottom"
        
        case partId = "r:part-id"
    }
    
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
        return .attribute
    }
    
    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        return .attribute
    }

}


struct PageModel: Codable, DynamicNodeDecoding, DynamicNodeEncoding {
    var xmlns: String
    var id: String //UUID
    var root: GroupModel // Group
    
    enum CodingKeys: String, CodingKey {
        case id
        case xmlns = "xmlns:my"
        case root = "my:group"
    }
    
    static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
        switch key {
        case CodingKeys.root:
            return .element
        default:
            return .attribute
        }
    }
    
    static func nodeEncoding(for key: CodingKey) -> XMLEncoder.NodeEncoding {
        switch key {
        case CodingKeys.root:
            return .element
        default:
            return .attribute
        }
    }
    
}

extension PageModel {

   static func testPageModel(url: URL) {

        do {
            
            let data = try Data.init(contentsOf: url)
            print("PageModel xml :")
            print(String(data: data, encoding: .utf8)!)

            let decoder = XMLDecoder()

            let pageModel = try decoder.decode(PageModel.self, from: data)

            print(pageModel)
            
            
            let header = XMLHeader(version: 1.0, encoding: "UTF-8")
            let encoder = XMLEncoder()
            
            encoder.outputFormatting = [.prettyPrinted]
            let returnData = try encoder.encode(pageModel, withRootKey: "my:page", header:header )

            print(String(data: returnData, encoding: .utf8)!)
            
        } catch {
            print("error in loading data from PageModel xml : \(error)")
        }
    }
}

Do you have any idea how i can do it?

@monibu91
Copy link
Author

I have also tried something like:

enum BlockChild: Equatable {
    
    case group(GroupModel)
    case text(TextModel)
    case image(ImageModel)
    case diagram(DiagramModel)
    case embed(EmbedModel)
}


extension BlockChild: Codable {
    enum CodingKeys: String, CodingKey {
        case group = "my:group"
        case text = "my:text"
        case image = "my:image"
        case diagram = "my:diagram"
        case embed = "my:embed"
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        switch self {
        case let .group(value):
            try container.encode(value, forKey: .group)
        case let .text(value):
            try container.encode(value, forKey: .text)
        case let .image(value):
            try container.encode(value, forKey: .image)
        case let .diagram(value):
            try container.encode(value, forKey: .diagram)
        case let .embed(value):
            try container.encode(value, forKey: .embed)
        }
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        
        if let tempGroup = try? container.decode(GroupModel.self, forKey: .group){
            self = .group(tempGroup)
        }
        else if let tempText = try? container.decode(TextModel.self, forKey: .text){
            self = .text(tempText)
        }
        else if let tempImage = try? container.decode(ImageModel.self, forKey: .image){
            self = .image(tempImage)
        }
        else if let tempDiagram = try? container.decode(DiagramModel.self, forKey: .diagram){
            self = .diagram(tempDiagram)
        }
        else {
            let tempEmbed = try container.decode(EmbedModel.self, forKey: .embed)
            self = .embed(tempEmbed)
        }
    }
}

But this give me error:

typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [XMLKey(stringValue: "0", intValue: 0), XMLKey(stringValue: "0", intValue: 0)], debugDescription: "Expected to decode Dictionary<String, Any> but found ChoiceBox instead.", underlyingError: nil))

@monibu91
Copy link
Author

monibu91 commented Mar 9, 2020

With the master branch my code works, but i was using cocoa-pods which i guess is an older version. So the fix for me was to add XMLCoder as Swift package pointing to master.

@MaxDesiatov
Copy link
Collaborator

Sorry for the delay, just having a look at this. A new version of XMLCoder will be tagged soon, which will make the fix available on CocoaPods. Thanks for reporting the issue!

@MaxDesiatov MaxDesiatov changed the title Can inheritance be implemented Can inheritance be implemented? Mar 16, 2020
@MaxDesiatov
Copy link
Collaborator

Closing as resolved in 0.10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants