{"id":13465615,"url":"https://github.com/gcharita/XMLMapper","last_synced_at":"2025-03-25T16:32:26.514Z","repository":{"id":25689725,"uuid":"105038946","full_name":"gcharita/XMLMapper","owner":"gcharita","description":"A simple way to map XML to Objects written in Swift","archived":false,"fork":false,"pushed_at":"2023-05-27T20:04:44.000Z","size":1474,"stargazers_count":111,"open_issues_count":4,"forks_count":21,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-05-29T10:56:57.579Z","etag":null,"topics":["carthage","cocoapods","soap","swift","swift-package-manager","xcode","xml","xml-mapping","xmlmapper"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gcharita.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-09-27T15:56:59.000Z","updated_at":"2024-05-29T10:56:57.580Z","dependencies_parsed_at":"2023-02-12T07:45:48.209Z","dependency_job_id":"94d6bde8-818c-4ec2-ad97-863014fc3d5e","html_url":"https://github.com/gcharita/XMLMapper","commit_stats":{"total_commits":185,"total_committers":2,"mean_commits":92.5,"dds":0.00540540540540535,"last_synced_commit":"6218f338c559f220c41d48828edce0b90f406a8d"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcharita%2FXMLMapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcharita%2FXMLMapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcharita%2FXMLMapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcharita%2FXMLMapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gcharita","download_url":"https://codeload.github.com/gcharita/XMLMapper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222088583,"owners_count":16928982,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["carthage","cocoapods","soap","swift","swift-package-manager","xcode","xml","xml-mapping","xmlmapper"],"created_at":"2024-07-31T15:00:32.659Z","updated_at":"2024-10-29T17:31:14.634Z","avatar_url":"https://github.com/gcharita.png","language":"Swift","funding_links":[],"categories":["Libs","Data Management [🔝](#readme)"],"sub_categories":["Data Management"],"readme":"# XMLMapper\n\n[![CI Status](https://img.shields.io/travis/gcharita/XMLMapper.svg?style=flat)](https://travis-ci.org/gcharita/XMLMapper)\n[![Version](https://img.shields.io/cocoapods/v/XMLMapper.svg?style=flat)](http://cocoapods.org/pods/XMLMapper)\n[![License](https://img.shields.io/cocoapods/l/XMLMapper.svg?style=flat)](http://cocoapods.org/pods/XMLMapper)\n[![Platform](https://img.shields.io/cocoapods/p/XMLMapper.svg?style=flat)](http://cocoapods.org/pods/XMLMapper)\n[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\nXMLMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from XML.\n\n- [Example](#example)\n- [Requirements](#requirements)\n- [Definition of the protocols](#definition-of-the-protocols)\n- [How to use](#how-to-use)\n  - [Basic XML mapping](#basic-xml-mapping)\n  - [Advanced mapping](#advanced-mapping)\n  - [Swift 4.2 and unordered XML elements](#swift-42-and-unordered-xml-elements)\n  - [Map CDATA wrapped values](#map-cdata-wrapped-values)\n  - [XML Mapping example](#xml-Mapping-example)\n- [Requests subspec](#requests-subspec)\n- [Communication](#communication)\n- [Installation](#installation)\n- [Special thanks](#special-thanks)\n- [License](#license)\n\n## Example\n\nTo run the example project, clone the repo, and run `pod install` from the Example directory first.\n\n## Requirements\n\n- iOS 8.0+ / macOS 10.9+ / tvOS 9.0+ / watchOS 2.0+\n- Xcode 9.1+\n- Swift 3.1+\n\n## Definition of the protocols\n\n### `XMLBaseMappable` Protocol\n\n#### `var nodeName: String! { get set }`\n\nThis property is where the name of the XML node is being mapped\n\n#### `mutating func mapping(map: XMLMap)`\n\nThis function is where all mapping definitions should go. When parsing XML, this function is executed after successful object creation. When generating XML, it is the only function that is called on the object.\n\nNote: This protocol should not be implemented directly. `XMLMappable` or `XMLStaticMappable` should be used instead\n\n### `XMLMappable` Protocol (sub protocol of `XMLBaseMappable`)\n\n#### `init?(map: XMLMap)`\n\nThis failable initializer is used by XMLMapper for object creation. It can be used by developers to validate XML prior to object serialization. Returning nil within the function will prevent the mapping from occuring. You can inspect the `XML` stored within the `XMLMap` object to do your validation:\n\n```swift\nrequired init?(map: XMLMap) {\n    // check if a required \"id\" element exists within the XML.\n    if map.XML[\"id\"] == nil {\n        return nil\n    }\n}\n```\n\n### `XMLStaticMappable` Protocol (sub protocol of `XMLBaseMappable`)\n\n`XMLStaticMappable` is an alternative to `XMLMappable`. It provides developers with a static function that is used by XMLMapper for object initialization instead of `init?(map: XMLMap)`.\n\n#### `static func objectForMapping(map: XMLMap) -\u003e XMLBaseMappable?`\n\nXMLMapper uses this function to get objects to use for mapping. Developers should return an instance of an object that conforms to `XMLBaseMappable` in this function. This function can also be used to:\n\n- validate XML prior to object serialization\n- provide an existing cached object to be used for mapping\n- return an object of another type (which also conforms to `XMLBaseMappable`) to be used for mapping. For instance, you may inspect the XML to infer the type of object that should be used for mapping\n\nIf you need to implement XMLMapper in an extension, you will need to adopt this protocol instead of `XMLMappable`.\n\n## How to use\n\nTo support mapping, a class or struct just needs to implement the `XMLMappable` protocol:\n\n```swift\nvar nodeName: String! { get set }\ninit?(map: XMLMap)\nmutating func mapping(map: XMLMap)\n```\n\nXMLMapper uses the `\u003c-` operator to define how each property maps to and from XML:\n\n```xml\n\u003cfood\u003e\n  \u003cname\u003eBelgian Waffles\u003c/name\u003e\n  \u003cprice\u003e5.95\u003c/price\u003e\n  \u003cdescription\u003e\n    Two of our famous Belgian Waffles with plenty of real maple syrup\n  \u003c/description\u003e\n  \u003ccalories\u003e650\u003c/calories\u003e\n\u003c/food\u003e\n```\n\n```swift\nclass Food: XMLMappable {\n    var nodeName: String!\n\n    var name: String!\n    var price: Float!\n    var description: String?\n    var calories: Int?\n\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        name \u003c- map[\"name\"]\n        price \u003c- map[\"price\"]\n        description \u003c- map[\"description\"]\n        calories \u003c- map[\"calories\"]\n    }\n}\n```\n\nXMLMapper can map classes or structs composed of the following types:\n\n- `Int`\n- `Bool`\n- `Double`\n- `Float`\n- `String`\n- `RawRepresentable` (Enums)\n- `Array\u003cAny\u003e`\n- `Dictionary\u003cString, Any\u003e`\n- `Object\u003cT: XMLBaseMappable\u003e`\n- `Array\u003cT: XMLBaseMappable\u003e`\n- `Set\u003cT: XMLBaseMappable\u003e`\n- `Dictionary\u003cString, T: XMLBaseMappable\u003e`\n- `Dictionary\u003cString, Array\u003cT: XMLBaseMappable\u003e\u003e`\n- Optionals and Implicitly Unwrapped Optionals of all the above\n\n### Basic XML mapping\n\nConvert easily an XML string to `XMLMappable`:\n\n```swift\nlet food = Food(XMLString: xmlString)\n```\n\nOr an `XMLMappable` object to XML string:\n\n```swift\nlet xmlString = food.toXMLString()\n```\n\n`XMLMapper` class can also provide the same functionality:\n\n```swift\nlet food = XMLMapper\u003cFood\u003e().map(XMLString: xmlString)\n\nlet xmlString = XMLMapper().toXMLString(food)\n```\n\n### Advanced mapping\n\nSet `nodeName` property of your class to change the element's name:\n\n```swift\nfood.nodeName = \"myFood\"\n```\n\n```xml\n\u003cmyFood\u003e\n  \u003cname\u003eBelgian Waffles\u003c/name\u003e\n  \u003cprice\u003e5.95\u003c/price\u003e\n  \u003cdescription\u003e\n    Two of our famous Belgian Waffles with plenty of real maple syrup\n  \u003c/description\u003e\n  \u003ccalories\u003e650\u003c/calories\u003e\n\u003c/myFood\u003e\n```\n\nMap easily XML attributes using the `attributes` property of the `XMLMap`:\n\n```xml\n\u003cfood name=\"Belgian Waffles\"\u003e\n\u003c/food\u003e\n```\n\n```swift\nfunc mapping(map: XMLMap) {\n    name \u003c- map.attributes[\"name\"]\n}\n```\n\nMap array of elements:\n\n```xml\n\u003cbreakfast_menu\u003e\n  \u003cfood\u003e\n    \u003cname\u003eBelgian Waffles\u003c/name\u003e\n    \u003cprice\u003e5.95\u003c/price\u003e\n    \u003cdescription\u003e\n      Two of our famous Belgian Waffles with plenty of real maple syrup\n    \u003c/description\u003e\n    \u003ccalories\u003e650\u003c/calories\u003e\n  \u003c/food\u003e\n  \u003cfood\u003e\n    \u003cname\u003eStrawberry Belgian Waffles\u003c/name\u003e\n    \u003cprice\u003e7.95\u003c/price\u003e\n    \u003cdescription\u003e\n      Light Belgian waffles covered with strawberries and whipped cream\n    \u003c/description\u003e\n    \u003ccalories\u003e900\u003c/calories\u003e\n  \u003c/food\u003e\n\u003c/breakfast_menu\u003e\n```\n\n```swift\nfunc mapping(map: XMLMap) {\n    foods \u003c- map[\"food\"]\n}\n```\n\nCreate your own custom transform type by implementing the `XMLTransformType` protocol:\n\n```swift\npublic protocol XMLTransformType {\n    associatedtype Object\n    associatedtype XML\n\n    func transformFromXML(_ value: Any?) -\u003e Object?\n    func transformToXML(_ value: Object?) -\u003e XML?\n}\n```\n\nand use it in mapping:\n\n```swift\nfunc mapping(map: XMLMap) {\n    startTime \u003c- (map[\"starttime\"], XMLDateTransform())\n}\n```\n\nMap nested XML elements by separating names with a dot:\n\n```xml\n\u003cfood\u003e\n  \u003cdetails\u003e\n    \u003cprice\u003e5.95\u003c/price\u003e\n  \u003c/details\u003e\n\u003c/food\u003e\n```\n\n```swift\nfunc mapping(map: XMLMap) {\n    price \u003c- map[\"details.price\"]\n}\n```\n\n---\n**Note:** Nested mapping is currently supported only:\n\n- for elements that are composed of only innerText (like the above example) and\n- for attributes\n\nThis means that in order to map the actual price of the food in the following XML:\n\n```xml\n\u003cfood\u003e\n  \u003cdetails\u003e\n    \u003cprice currency=\"euro\"\u003e5.95\u003c/price\u003e\n  \u003c/details\u003e\n\u003c/food\u003e\n```\n\nYou need to use an XMLMappable object instead of a `Float`:\n\n```swift\nclass Price: XMLMappable {\n    var nodeName: String!\n\n    var currency: String!\n    var actualPrice: Float!\n\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        currency \u003c- map.attributes[\"currency\"]\n        actualPrice \u003c- map.innerText\n    }\n}\n```\n\nBecause of `currency` attribute existence. The same applies to the following XML:\n\n```xml\n\u003cfood\u003e\n  \u003cdetails\u003e\n    \u003cprice\u003e\n      5.95\n      \u003ccurrency\u003eeuro\u003c/currency\u003e\n  \u003c/details\u003e\n\u003c/food\u003e\n```\n\nYou need to use an XMLMappable object like:\n\n```swift\nclass Price: XMLMappable {\n    var nodeName: String!\n\n    var currency: String!\n    var actualPrice: Float!\n\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        currency \u003c- map[\"currency\"]\n        actualPrice \u003c- map.innerText\n    }\n}\n```\n\nBecause of `currency` element existence.\n\n---\n\n### Swift 4.2 and unordered XML elements\n\nStarting from Swift 4.2, XML elements are highly likely to have different order each time you run your app. (This happens because they are represented by a `Dictionary`)\n\nFor this, since version 1.5.2 of the XMLMapper you can map and change the order of the nodes that appear inside another node using `nodesOrder` property of `XMLMap`:\n\n```swift\nclass TestOrderedNodes: XMLMappable {\n    var nodeName: String!\n\n    var id: String?\n    var name: String?\n    var nodesOrder: [String]?\n\n    init() {}\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        id \u003c- map[\"id\"]\n        name \u003c- map[\"name\"]\n        nodesOrder \u003c- map.nodesOrder\n    }\n}\n\nlet testOrderedNodes = TestOrderedNodes()\ntestOrderedNodes.id = \"1\"\ntestOrderedNodes.name = \"the name\"\ntestOrderedNodes.nodesOrder = [\"id\", \"name\"]\nprint(testOrderedNodes.toXMLString() ?? \"nil\")\n```\n\n**Note:** If you want to change the ordering of the nodes, make sure that you include, in the `nodesOrder` array, all the node names that you want to appear in the XML string\n\n### Map CDATA wrapped values\n\nSince version 2.0.0 of XMLMapper, **CDATA** support has added. CDATA wrapped strings now are mapped as an `Array\u003cData\u003e` by default, instead of `String` which was the case in the previous versions. That had as a side effect the disability to **serialize** CDATA wrapped values.\n\nFor example using the following code:\n\n```swift\nclass Food: XMLMappable {\n    var nodeName: String!\n    \n    var description: String?\n    \n    init() {}\n    \n    required init?(map: XMLMap) {}\n        \n    func mapping(map: XMLMap) {\n        description \u003c- map[\"description\"]\n    }\n}\n\nlet food = Food()\nfood.nodeName = \"Food\"\nfood.description = \"Light Belgian waffles covered with strawberries \u0026 whipped cream\"\nprint(food.toXMLString() ?? \"nil\")\n```\n\nYour result was always:\n\n```xml\n\u003cFood\u003e\n    \u003cdescription\u003e\n        Light Belgian waffles covered with strawberries \u0026amp; whipped cream\n    \u003c/description\u003e\n\u003c/Food\u003e\n```\n\nIn version *2.0.0* we introduce the build in `XMLCDATATransform` type, which can be used like this:\n\n```swift\nclass Food: XMLMappable {\n    var nodeName: String!\n    \n    var description: String?\n    \n    init() {}\n    \n    required init?(map: XMLMap) {}\n        \n    func mapping(map: XMLMap) {\n        description \u003c- (map[\"description\"], XMLCDATATransform())\n    }\n}\n\nlet food = Food()\nfood.nodeName = \"Food\"\nfood.description = \"Light Belgian waffles covered with strawberries \u0026 whipped cream\"\nprint(food.toXMLString() ?? \"nil\")\n```\n\nand the result will be:\n\n```xml\n\u003cFood\u003e\n    \u003cdescription\u003e\n        \u003c![CDATA[\n            Light Belgian waffles covered with strawberries \u0026 whipped cream\n        ]]\u003e\n    \u003c/description\u003e\n\u003c/Food\u003e\n```\n\nThe **breaking change** here is that the deserialization of CDATA wrapped values cannot achieved, unless you use `XMLCDATATransform` type. For example if you try to map the above XML to the following model class:\n\n```swift\nclass Food: XMLMappable {\n    var nodeName: String!\n    \n    var description: String?\n    \n    required init?(map: XMLMap) {}\n        \n    func mapping(map: XMLMap) {\n        description \u003c- map[\"description\"]\n    }\n}\n```\n\nYou will end up with `nil` as the value of `description` property.\n\n---\n**Note**: That default behaviour can be changed if you run `xmlObject(withString:encoding:options:)` function of `XMLSerialization` yourself and pass as `options` the `default` set, including `cdataAsString` option.\n\nFor example, the following code will work:\n\n```swift\nclass Food: XMLMappable {\n    var nodeName: String!\n    \n    var description: String?\n    \n    required init?(map: XMLMap) {}\n        \n    func mapping(map: XMLMap) {\n        description \u003c- map[\"description\"]\n    }\n}\n\nlet xmlString = \"\"\"\n\u003cFood\u003e\n    \u003cdescription\u003e\n        \u003c![CDATA[\n            Light Belgian waffles covered with strawberries \u0026 whipped cream\n        ]]\u003e\n    \u003c/description\u003e\n\u003c/Food\u003e\n\"\"\"\nlet data = Data(xmlString.utf8) // Data for deserialization (from XML to object)\ndo {\n    let xml = try XMLSerialization.xmlObject(with: data, options: [.default, .cdataAsString])\n    let food = XMLMapper\u003cFood\u003e().map(XMLObject: xml)\n} catch {\n    print(error)\n}\n```\n\n---\n\n### XML Mapping example\n\nmap XML:\n\n```xml\n \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n \u003croot\u003e\n    \u003cTestElementXMLMappable testAttribute=\"enumValue\"\u003e\n        \u003ctestString\u003eTest string\u003c/testString\u003e\n        \u003ctestList\u003e\n            \u003celement\u003e\n                \u003ctestInt\u003e1\u003c/testInt\u003e\n                \u003ctestDouble\u003e1.0\u003c/testDouble\u003e\n            \u003c/element\u003e\n            \u003celement\u003e\n                \u003ctestInt\u003e2\u003c/testInt\u003e\n                \u003ctestDouble\u003e2.0\u003c/testDouble\u003e\n            \u003c/element\u003e\n            \u003celement\u003e\n                \u003ctestInt\u003e3\u003c/testInt\u003e\n                \u003ctestDouble\u003e3.0\u003c/testDouble\u003e\n            \u003c/element\u003e\n            \u003celement\u003e\n                \u003ctestInt\u003e4\u003c/testInt\u003e\n                \u003ctestDouble\u003e4.0\u003c/testDouble\u003e\n            \u003c/element\u003e\n        \u003c/testList\u003e\n        \u003csomeTag\u003e\n            \u003csomeOtherTag\u003e\n                \u003cnestedTag testNestedAttribute=\"nested attribute\"\u003e\n                \u003c/nestedTag\u003e\n            \u003c/someOtherTag\u003e\n        \u003c/someTag\u003e\n    \u003c/TestElementXMLMappable\u003e\n \u003c/root\u003e\n```\n\nto classes:\n\n```swift\nclass TestXMLMappable: XMLMappable {\n    var nodeName: String!\n\n    var testElement: TestElementXMLMappable!\n    var testNestedAttribute: String?\n\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        testElement \u003c- map[\"TestElementXMLMappable\"]\n        testNestedAttribute \u003c- map.attributes[\"TestElementXMLMappable.someTag.someOtherTag.nestedTag.testNestedAttribute\"]\n    }\n}\n\nenum EnumTest: String {\n    case theEnumValue = \"enumValue\"\n}\n\nclass TestElementXMLMappable: XMLMappable {\n    var nodeName: String!\n\n    var testString: String?\n    var testAttribute: EnumTest?\n    var testList: [Element]?\n    var nodesOrder: [String]?\n\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        testString \u003c- map[\"testString\"]\n        testAttribute \u003c- map.attributes[\"testAttribute\"]\n        testList \u003c- map[\"testList.element\"]\n        nodesOrder \u003c- map.nodesOrder\n    }\n}\n\nclass Element: XMLMappable {\n    var nodeName: String!\n\n    var testInt: Int?\n    var testDouble: Float?\n\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        testInt \u003c- map[\"testInt\"]\n        testDouble \u003c- map[\"testDouble\"]\n    }\n}\n```\n\n## Requests subspec\n\n**Note:** `Requests` subspec has different minimum deployment targets due to `Alamofire` dependency. (currently **iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+**)\n\nCreate and send easily request with XML body using `Alamofire` (added missing `XMLEncoding` struct)\n\n```swift\nAlamofire.request(url, method: .post, parameters: xmlMappableObject.toXML(), encoding: XMLEncoding.default)\n```\n\nAlso map XML responses to `XMLMappable` objects using the `Alamofire` extension. For example a URL returns the following CD catalog:\n\n```xml\n\u003cCATALOG\u003e\n    \u003cCD\u003e\n        \u003cTITLE\u003eEmpire Burlesque\u003c/TITLE\u003e\n        \u003cARTIST\u003eBob Dylan\u003c/ARTIST\u003e\n        \u003cCOUNTRY\u003eUSA\u003c/COUNTRY\u003e\n        \u003cCOMPANY\u003eColumbia\u003c/COMPANY\u003e\n        \u003cPRICE\u003e10.90\u003c/PRICE\u003e\n        \u003cYEAR\u003e1985\u003c/YEAR\u003e\n    \u003c/CD\u003e\n    \u003cCD\u003e\n        \u003cTITLE\u003eHide your heart\u003c/TITLE\u003e\n        \u003cARTIST\u003eBonnie Tyler\u003c/ARTIST\u003e\n        \u003cCOUNTRY\u003eUK\u003c/COUNTRY\u003e\n        \u003cCOMPANY\u003eCBS Records\u003c/COMPANY\u003e\n        \u003cPRICE\u003e9.90\u003c/PRICE\u003e\n        \u003cYEAR\u003e1988\u003c/YEAR\u003e\n    \u003c/CD\u003e\n\u003c/CATALOG\u003e\n```\n\nMap the response as follows:\n\n```swift\nAlamofire.request(url).responseXMLObject { (response: DataResponse\u003cCDCatalog\u003e) in\n    let catalog = response.result.value\n    print(catalog?.cds?.first?.title ?? \"nil\")\n}\n```\n\nThe `CDCatalog` object will look something like this:\n\n```swift\nclass CDCatalog: XMLMappable {\n    var nodeName: String!\n\n    var cds: [CD]?\n\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        cds \u003c- map[\"CD\"]\n    }\n}\n\nclass CD: XMLMappable {\n    var nodeName: String!\n\n    var title: String!\n    var artist: String?\n    var country: String?\n    var company: String?\n    var price: Double?\n    var year: Int?\n\n    required init?(map: XMLMap) {}\n\n    func mapping(map: XMLMap) {\n        title \u003c- map[\"TITLE\"]\n        artist \u003c- map[\"ARTIST\"]\n        country \u003c- map[\"COUNTRY\"]\n        company \u003c- map[\"COMPANY\"]\n        price \u003c- map[\"PRICE\"]\n        year \u003c- map[\"YEAR\"]\n    }\n}\n```\n\nLast but not least, create easily and send SOAP requests, again using `Alamofire`:\n\n```swift\nlet soapMessage = SOAPMessage(soapAction: \"ActionName\", nameSpace: \"ActionNameSpace\")\nlet soapEnvelope = SOAPEnvelope(soapMessage: soapMessage)\n\nAlamofire.request(url, method: .post, parameters: soapEnvelope.toXML(), encoding: XMLEncoding.soap(withAction: \"ActionNameSpace#ActionName\"))\n```\n\nThe request will look something like this:\n\n```http\nPOST / HTTP/1.1\nHost: \u003cThe url\u003e\nContent-Type: text/xml; charset=\"utf-8\"\nConnection: keep-alive\nSOAPAction: ActionNameSpace#ActionName\nAccept: */*\nUser-Agent: XMLMapper_Example/1.0 (org.cocoapods.demo.XMLMapper-Example; build:1; iOS 11.0.0) Alamofire/4.5.1\nAccept-Language: en;q=1.0\nContent-Length: 251\nAccept-Encoding: gzip;q=1.0, compress;q=0.5\n\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003csoap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" soap:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"\u003e\n    \u003csoap:Body\u003e\n        \u003cm:ActionName xmlns:m=\"ActionNameSpace\"/\u003e\n    \u003c/soap:Body\u003e\n\u003c/soap:Envelope\u003e\n```\n\nAdding action parameters is as easy as subclassing the `SOAPMessage` class.\n\n```swift\nclass MySOAPMessage: SOAPMessage {\n\n    // Custom properties\n\n    override func mapping(map: XMLMap) {\n        super.mapping(map: map)\n\n        // Map the custom properties\n    }\n}\n```\n\nAlso specify the SOAP version that the endpoint use as follows:\n\n```swift\nlet soapMessage = SOAPMessage(soapAction: \"ActionName\", nameSpace: \"ActionNameSpace\")\nlet soapEnvelope = SOAPEnvelope(soapMessage: soapMessage, soapVersion: .version1point2)\n\nAlamofire.request(url, method: .post, parameters: soapEnvelope.toXML(), encoding: XMLEncoding.soap(withAction: \"ActionNameSpace#ActionName\", soapVersion: .version1point2))\n```\n\nand the request will change to this:\n\n```http\nPOST / HTTP/1.1\nHost: \u003cThe url\u003e\nContent-Type: application/soap+xml;charset=UTF-8;action=\"ActionNameSpace#ActionName\"\nConnection: keep-alive\nAccept: */*\nUser-Agent: XMLMapper_Example/1.0 (org.cocoapods.demo.XMLMapper-Example; build:1; iOS 11.0.0) Alamofire/4.5.1\nAccept-Language: en;q=1.0\nContent-Length: 248\nAccept-Encoding: gzip;q=1.0, compress;q=0.5\n\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003csoap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope/\" soap:encodingStyle=\"http://www.w3.org/2003/05/soap-encoding\"\u003e\n    \u003csoap:Body\u003e\n        \u003cm:ActionName xmlns:m=\"ActionNameSpace\"/\u003e\n    \u003c/soap:Body\u003e\n\u003c/soap:Envelope\u003e\n```\n\nUnfortunately, there isn't an easy way to map SOAP response, other than creating your own XMLMappable objects (at least not for the moment)\n\n## Communication\n\n- If you **need help**, use [Stack Overflow](https://stackoverflow.com/questions/tagged/xmlmapper). (Tag 'xmlmapper')\n- If you'd like to **ask a general question**, use [Stack Overflow](https://stackoverflow.com/questions/tagged/xmlmapper).\n- If you **found a bug**, open an issue.\n- If you **have a feature request**, open an issue.\n\n## Installation\n\n### CocoaPods\n\nXMLMapper is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your `Podfile`:\n\n```ruby\npod 'XMLMapper'\n```\n\nTo install the `Requests` subspec add the following line to your `Podfile`:\n\n```ruby\npod 'XMLMapper/Requests'\n```\n\n### Carthage\n\nTo integrate XMLMapper into your Xcode project using [Carthage](https://github.com/Carthage/Carthage), add the following line to your  `Cartfile`:\n\n```ogdl\ngithub \"gcharita/XMLMapper\" ~\u003e 1.6\n```\n\n### Swift Package Manager\n\nTo add XMLMapper to a [Swift Package Manager](https://swift.org/package-manager/) based project, add the following:\n\n```swift\n.package(url: \"https://github.com/gcharita/XMLMapper.git\", from: \"1.6.0\")\n```\n\nto the `dependencies` value of your `Package.swift`.\n\n## Special thanks\n\n- Special thanks to [Tristan Himmelman](https://github.com/tristanhimmelman). This project is based in  [ObjectMapper](https://github.com/tristanhimmelman/ObjectMapper) for the most part, which is a great solution for JSON mapping. Also the Requests subspec is based on [AlamofireObjectMapper](https://github.com/tristanhimmelman/AlamofireObjectMapper).\n- A special thanks to [Nick Lockwood](https://github.com/nicklockwood) and his idea behind [XMLDictionary](https://github.com/nicklockwood/XMLDictionary)\n- A special thanks to [Alamofire](https://github.com/Alamofire/Alamofire) for the subspec dependency\n\n## License\n\nXMLMapper is available under the MIT license. See the [LICENSE](LICENSE) file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgcharita%2FXMLMapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgcharita%2FXMLMapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgcharita%2FXMLMapper/lists"}