gcharita / XMLMapper

A simple way to map XML to Objects written in Swift
MIT License
111 stars 21 forks source link

Add UTF-16 support #13

Open gianfilippocisternino opened 6 years ago

gianfilippocisternino commented 6 years ago

Can you please add support for UTF-16?

gcharita commented 6 years ago

This is an interesting addition. I will try to implement it somehow, but this is a bit difficult. Until this is done, there is a workaround that you can use.

Map an UTF-16 encoded XML to XMLMappable object.

Using XMLSerialization you can convert your XML string to a Dictionary passing the correct encoding:

do {
    let dict = try XMLSerialization.xmlObject(withString: xmlString, using: .utf16) as? [String: Any]
} catch {
    print("Serialization error occurred")
}

And then use this Dictionary in map(XML:) function of XMLMapper:

let object = XMLMapper<TestXMLMappable>().map(XML: dict)

Convert XMLMappable object to string

For the serialization process you can convert your XMLMappable object to string using the toXMLString() function:

var xmlString = object?.toXMLString()

And then append the correct XML declaration:

xmlString = "<?xml version=\"1.0\" encoding=\"utf-16\"?>\n\(xmlString)"
gianfilippocisternino commented 6 years ago

I already added a workaround because i needed to use as a response mapper with Alamofire. I just did a search of "utf-16" inside the xml string (is ugly, i know), but it works. It would be better to search the attribute "encoding" inside the response, and than try to decode using that.

gcharita commented 6 years ago

Yes, this is what should be done. I will try to find a clean way to do it. Thank you.

martinho13 commented 6 years ago

Why the Chinese in XML model cannot display corret?

Just show 皇后大道中5號衡怡大廈地ä

gcharita commented 6 years ago

@martinho13 probably because your XML is not utf-8 encoded. Try using my first comment in this issue and replace .utf16 with the encoding that works best with your XML.

martinho13 commented 6 years ago

i tried it but still not work

gcharita commented 6 years ago

@martinho13 could you provide a sample of your XML to test if this an issue of the native XMLParser?

martinho13 commented 6 years ago
 <addresses>
<address lang="en_US">
<![CDATA[ Johnston Road, Wan Chai ]]>
</address>
<address lang="zh_TW">
<![CDATA[ 灣仔莊士敦道 ]]>
</address>
<address lang="zh_CN">
<![CDATA[ 湾仔庄士敦道 ]]>
</address>
</addresses>

Please help for this case

gcharita commented 6 years ago

@martinho13 you are probably using the default XMLCDATATransform from enhancement/cdata-mapping branch as mentioned in #14. In your case you have to use a custom XMLTransformType or a subclass of XMLCDATATransform.

Here is an example:

class XMLCustomCDATATransform: XMLTransformType {
    typealias Object = String
    typealias XML = [Data]

    private let encoding: String.Encoding

    init(encoding: String.Encoding = .utf8) {
        self.encoding = encoding
    }

    func transformFromXML(_ value: Any?) -> Object? {
        guard let cdata = value as? [Data] else {
            return nil
        }
        return cdata.compactMap({ String(data: $0, encoding: encoding) }).joined(separator: "\n")
    }

    func transformToXML(_ value: Object?) -> XML? {
        guard let cdata = value?.data(using: encoding) else {
            return nil
        }
        return [cdata]
    }
}

You can use this custom XMLTransformType in mapping(map:) function like:

innerCDATA <- (map.innerCDATA, XMLCustomCDATATransform(encoding: .utf16))

Hope this helps.