gcharita / xmlmapper Goto Github PK
View Code? Open in Web Editor NEWA simple way to map XML to Objects written in Swift
License: MIT License
A simple way to map XML to Objects written in Swift
License: MIT License
Hi guys,
Almost of times the app crash with random xmls on this line.
func addText(_ additionalText: String) { if case nil = text?.append(additionalText) { text = additionalText } }
It throws this exception on console:
(17940,0x70000e800000) malloc: *** error for object 0x600000862ac0: Non-aligned pointer being freed (2) *** set a breakpoint in malloc_error_break to debug
Could you help me? :)
Hello, I am trying to compose a SOAP request and have encountered a problem - for some reason in my request Body is located before Header and I don't understand how I can change it.
This is how I create SOAPEnvelope where is information has header data and soapMessage has body data:
let soapEnvelope = SOAPEnvelope(soapMessage: soapMessage, soapInformation: information, soapVersion: .version1point2)
And for example when I try to print SOAPEnvelope (soapEnvelope.toXMLString()) I receive this string:
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding" xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Body> .... </soap:Body> <soap:Header> ... </soap:Header> </soap:Envelope>
The problem is that I work with the ONVIF service and it is sensitive to the order of the header / body.
Thanks
Trying to map the following xml:
<apps>
<app id="tvinput.dtv" type="tvin" version="1.0.0">Antenna TV</app>
<app id="tvinput.hdmi2" type="tvin" version="1.0.0">Apple TV</app>
<app id="12" subtype="ndka" type="appl" version="4.2.81179021">Netflix</app>
<app id="2531" subtype="rsga" type="appl" version="4.3.2018073101">NHL</app>
</apps>
using
class Apps: XMLMappable {
var nodeName: String!
var apps: [App]!
required init?(map: XMLMap) {}
func mapping(map: XMLMap) {
apps <- map["App"]
}
}
class App: XMLMappable {
var nodeName: String!
var name: String?
var id: String?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
name <- map.innertext
id <- map.attributes["id"]
}
}
and getting nil from Apps(XMLString: string)!.apps
where variable string
has the correct xml.
Do you have any pointer how could I get an array containing all "app" nodes (name and id) as separate items?
Hi,
I’m trying to use the XMLEncoding that is part of the Request target but I'm seeing that it is excluded in Package.swift
I know I can achieve this with CocoaPods but is it possible to achieve the same with SPM?
Thanks in advance.
It is impossible to correctly parse elements that use innerText and optional attributes.
Take the example in the README:
<food>
<details>
<price currency="euro">5.95</price>
</details>
</food>
class Price: XMLMappable {
var nodeName: String!
var currency: String!
var actualPrice: Float!
required init?(map: XMLMap) {}
func mapping(map: XMLMap) {
currency <- map.attributes["currency"]
actualPrice <- map.innerText
}
}
In this case, if the currency is optional so the input could include either <price currency="euro">5.95</price>
or <price>5.95</price>
, you cannot correctly parse the latter example. This is because the collapseTextNodes
functionality in XMLObjectParser
moves the 5.95
value to the parent dictionary if there are no attributes on the node. This leaves you with no reasonable way to parse both inputs with the same mapping object.
Hello @gcharita , thanks for this great library. It is well appreciated.
I will like to ask how best I can store data to my UserDefaults.
I have already tried
func saveListData(podList: [RSSFeeds]){
let podData = NSKeyedArchiver.archivedData(withRootObject: podList)
UserDefaults.standard.set(podData, forKey: "podData")
}
but i am getting the unrecognized selector sent to instance 0x600000c23040 error.
Any insight to getting this resolved will be well appreciated.
Regards,
I've just cloned the alamofire git as a sibmodule in my project along with your project, when I compile I get a load of errors including "DataRequest.stringResponseSerializer" not being found and so on....
Is this only compatible with a specific maor version?
Mapping an XML element that have other elements of basic type and attributes:
<Person gender="male">
<FirstName>First</FirstName>
<LastName>Last</LastName>
</Person>
is easy:
class Person: XMLMappable {
var nodeName: String!
var gender: String?
var firstName: String?
var lastName: String?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
gender <- map.attributes["gender"]
firstName <- map["FirstName"]
lastName <- map["LastName"]
}
}
But if I try to map an XML element of basic type (like Person
below) that have attributes:
<root>
<Person gender="male">First Last</Person>
</root>
Using this:
class Root: XMLMappable {
var nodeName: String!
var person: String?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
person <- map["Person"]
}
}
I am getting nil
in person
property and using this:
class Root: XMLMappable {
var nodeName: String!
var person: Person?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
person <- map["Person"]
}
}
class Person: XMLMappable {
var nodeName: String!
var gender: String?
var name: String?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
gender <- map.attributes["gender"]
//name <- get somehow innertext
}
}
I am getting correctly the gender
attribute but I don't know how to get Person
's name.
Hi!
How would I go about handling recursive XML elements?
E.g.
<item>
<id>1</id>
<item>
<id>2</id>
</item>
</item>
Hi Gcharita,
This code is not working, there is a dot in the middle of LINE.NAME
func mapping(map: XMLMap) {
lineName <- map["LINE.NAME"]
This code is fully working. There is no dot in the middle of LINENAME
func mapping(map: XMLMap) {
lineName <- map["LINENAME"]
thanks in advance,
Patrick
There is an issue on mapping simple tags (a tag with just inner text) that have optional attributes.
When there is at least one attribute present, everything work fine:
<root>
<tag optionalAttribute="attribute value">innetText</testString>
</root>
But when there is no attribute present:
<root>
<tag>innetText</testString>
</root>
mapping using the same model produces nil
:
class Root: XMLMappable {
var nodeName: String!
var tag: Tag?
required init?(map: XMLMap) {}
func mapping(map: XMLMap) {
tag <- map["tag"]
}
}
class Tag: XMLMappable {
var nodeName: String!
var optionalAttribute: String?
var text: String?
required init?(map: XMLMap) {}
func mapping(map: XMLMap) {
optionalAttribute <- map.attributes["optionalAttribute"]
text <- map.innerText
}
}
I have an xml file that has an element that is a flag. For example, <hasThing/>. If that element exists I want to map it to true, otherwise it should be mapped to false. I didn't see anything in the readme. Is there a way to do this?
Thanks.
I think there is problem in XMLParserHelper class func xmlString in nodes with attributes only.
Suggest change string format "<%1$@>%2$@</%1$@>" to "<%1$@%2$@/>" in
if !innerXML.isEmpty { return String(format: "<%1$@%2$@>%3$@</%1$@>", nodeName, attributeString, innerXML) } else { return String(format: "<%1$@>%2$@</%1$@>", nodeName, attributeString)}
Can you please add support for UTF-16?
Any plans for supporting Alamofire 5?
Hi @gcharita,
Is that possible to parse just the first word or the portion I want from the xml?
ex:
In this case I need just the first word, "Belgian" from food.
<Response> <food>Belgian Waffles</food> </Response>
I have an XML Mappable Object that I use to map responses from our API:
`class CreateAccountResponse: XMLMappable {
var nodeName: String!
var Result: String!
var ResultExplanation: String!
required init?(map: XMLMap) {
nodeName = ApiConstants.XMLRootTag
}
func mapping(map: XMLMap) {
Result <- map["Result"]
ResultExplanation <- map["ResultExplanation"]
}`
and I'm using the Alamofire Requests subspec:
Alamofire.request(ApiProvider.buildUrl(), method: .post, parameters: requestObject.toXML(), encoding: XMLEncoding.default, headers: ApiConstants.Header) .responseXMLObject { (resp: DataResponse<CreateAccountResponse>) in {...}
And this works just perfect. Here is a example of and XML response that works:
<API3G> <Result>999</Result> <ResultExplanation>Email already in use</ResultExplanation> </API3G>
But the same endpoint with the same XML structure, but different values fails to map:
<API3G> <Result>902</Result> <ResultExplanation>Data mismatch in one of the fields - CustomerPassword. Please enter at least 6 characters (letters, numbers and !@#$%&()?)</ResultExplanation> </API3G>
The error message I'm getting is as follow: "XMLMapper failed to serialize response."
Question in subject.
Good day,
I found a problem when trying to connect to a foobar2000 server.
The server returns:
<upnp:artist>The 54 All-Stars</upnp:artist>
<upnp:artist role="AlbumArtist">Various Artists</upnp:artist>
And that's ok, because XMLMapper treats it like an array.
However, I can't access the second item, no matter what I try.
If I map it to a String, I just get the first item. Ok, that's fine, but the second item gets lost.
So then I tried creating a new class:
class SOAPItemAlbumArtist: XMLMappable {
required init?(map: XMLMap) {}
var nodeName: String!
var artistName: String?
var artistRole: String?
func mapping(map: XMLMap) {
artistName <- map.innerText
artistRole <- map.attributes["role"]
}
}
And then the definition is as such:
var artist: [SOAPItemAlbumArtist]?
That causes a crash in XMLMapper.swift:90
if var object = klass.init(map: map) as? N {
I tried everything I could to figure this out, including tracing through the source code but I'm not familiar enough with it to determine exactly how to fix it, or if I'm just setting up my mapping incorrectly.
Has anyone seen this issue? Is it a bug, or user error?
Example fragment:
<p eId="para_3">
Deputy <b>Sherrif</b> is going to rule this town.
</p>
This fails due to the <b>
element being a substring of the innerText.
Hi I'm using your library to map SOAP responses. I'm trying to call a PING function, but it always returns me nil
let soapMessage = SOAPMessage(soapAction: "Ping", nameSpace: actionNameSpace)
let soapEnvelope = SOAPEnvelope(soapMessage: soapMessage, soapVersion: .version1point2)
Alamofire.request(Url, method: .post, parameters: soapEnvelope.toXML(), encoding: XMLEncoding.soap(withAction: "\(actionNameSpace)#PingResponse", soapVersion: .version1point2)).responseXMLObject { (response: DataResponse<PingResponse>) in
print(response.result.value?.PingResult)
}
This is the request (tested with SoapUI)
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:tem="http://tempuri.org/">
<soap:Header/>
<soap:Body>
<tem:Ping/>
</soap:Body>
</soap:Envelope>
This is the response
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<PingResponse xmlns="http://tempuri.org/">
<PingResult>true</PingResult>
</PingResponse>
</soap:Body>
</soap:Envelope>
Can you help me?
When I write to XML string, I want to be in order attributes. How do I do this?
example:
class TestOrderedAttributes: XMLMappable {
var NodeName: String!
var attribute1: String?
var attribute2: String?
var attribute3: String?
init() {}
required init?(map:XMLMap) {}
func mapping(map: XMLMap) {
attribute1 <- map.attributes["attribute1"]
attribute2 <- map.attributes["attribute2"]
attribute3 <- map.attributes["attribute3"]
}
}
let testOrderedAttributes = TestOrderedAttributes()
testOrderedAttributes.attribute1 = "1"
testOrderedAttributes.attribute2= "2"
testOrderedAttributes.attribute3 = "3"
testOrderedAttributes.attributesOrder = ["attribute3", "attribute2", "attribute1"]
Mapping the following XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<test text="Foo & bar"/>
</root>
to the model:
class Root: XMLMappable {
var nodeName: String!
var testText: String?
required init?(map: XMLMap) {}
func mapping(map: XMLMap) {
testText <- map.attributes["test.text"]
}
}
and converting back the string calling toXMLString()
function, prints XML string but without XML encoding the attribute values:
<?xml version="1.0" encoding="utf-8"?>
<root>
<test text="Foo & bar"/>
</root>
CDATA deserialization works great out of the box. It would be great to create some approach to serialize CDATA wrapped values.
For example:
class MyData: XMLMappable {
var nodeName: String!
var cdataValue: String?
...
func mapping(map: XMLMap) {
cdataValue <- map.attributes["cdataValue"]
}
}
let myData = MyData()
myData.cdataValue = "actualValue"
print(myData.toXMLString())
<cdataValue><![CDATA[ actualValue ]]></cdataValue>
If we have XML something like
<Array>
<XMLMappable/>
</Array>
and try to map it like
var array = [XMLMappable]()
array <- map[Array.XMLMappable]
we have empty array instead of array with 1 item.
If think problem method is mapArray(XMLObject: Any?) -> [N]? in Core/XMLMapper.swift
Suggest add else if statement like this.
Before:
public func mapArray(XMLObject: Any?) -> [N]? {
if let XMLArray = XMLObject as? [[String: Any]] {
return mapArray(XMLArray: XMLArray)
}
return nil
}
After:
public func mapArray(XMLObject: Any?) -> [N]? {
if let XMLArray = XMLObject as? [[String: Any]] {
return mapArray(XMLArray: XMLArray)
} else if let object = XMLObject as? [String: Any] {
return mapArray(XMLArray: [object])
}
return nil
}
I have problem parsing this special characters ( <br />). In the xml tags there are also these symbols and html code. Can You help me?
Hi GCharita,
Since alamofire 5.2 i cannot convert DataResponse to expected type (DataResponse<T, AFError>).
Please find attached the used code and a screenshot of the error. Can you help me throught with this issue?
best regards,
Patrick
Alamofire 5.2
XMLMapper 2.0.0
Xcode 12.3
class AllCnannelModel : XMLMappable {
var nodeName: String!
var id : Int?
var name: String?
var url : URL?
var picture : URL?
var category_id: Int?
required init?(map: XMLMap) {}
func mapping(map: XMLMap) {
id<-map["PERSONID"]
name<-map["NAME"]
url<-map["url"]
picture<-map["picture"]
category_id<-map["category_id"]
}
}
let getallpersonsquery = GetAllPersonsQuery()
getallpersonsquery.nodeName = "query"
getallpersonsquery.sql = "SELECT personid, name FROM person where personid = 150"
AF.request(RequestUrl, method: .post, parameters: getallpersonsquery.toXML(), encoding: XMLEncoding.default, headers: headers)
.redirect(using: redirector)
.responseXMLObject(completionHandler: (DataResponse<[AllCnannelModel], AFError>) -> Void) in
}
}
Hello,
I am an employee of Monstarlab company. I have a question about the Privacy Manifest
At WWDC23 Apple announced that apps and SDKs that make use of certain "required reason" APIs etc will need to provide a privacy manifest.
Does XML Mapper need to include this manifest?
Please let me know about your upcoming plans to apply the privacy manifest.
Here are some useful references:
https://developer.apple.com/videos/play/wwdc2023/10060/
Thanks
Hi Gcharita,
I have an issue, I tried to search a lot of closed and open issues but couldn't find any results.
I have the xml like
<feed class="abcs-js">
<script/>
<startIndex>0</startIndex>
<itemCount>3</itemCount>
<totalCount>3</totalCount>
<item sdImg="https://i.image.com/sd.jpg" hdImg="https://i.image.com/hd.jpg">
<title>TITLE DEMO</title>
<description>Description demo</description>
<feed type="epose">https://abc.xml</feed>
</item>
<item sdImg="https://i.image.com/sd1.jpg" hdImg="https://i.image.com/hd1.jpg">
<title>TITLE DEMO</title>
<description>description demo</description>
<feed>https://xyz.xml</feed>
</item>
<item sdImg="https://i.image.com/sd2.jpg" hdImg="https://i.image.com/hd2.jpg">
<title>TITLE DEMO1</title>
<description>Description demo</description>
<feed type="grid">https://cyz.xml</feed>
</item>
</feed>
You can see, i have 2 tag <feed>
and my model like:
class Data: XMLMappable {
required init?(map: XMLMap) {}
var nodeName: String!
func mapping(map: XMLMap) {
startIndex <- map["startIndex"]
itemCount <- map["itemCount"]
totalCount <- map["totalCount"]
items <- map["item"]
}
var startIndex, itemCount, totalCount: Int?
var items: [Item]?
}
class Item: XMLMappable {
var title: String?
var feed: String?
var description: String?
var type: String?
var sdImg: String?
var hdImg: String?
var nodeName: String!
required init?(map: XMLMap) {}
func mapping(map: XMLMap) {
title <- map["title"]
titlel <- map["titlel"]
feed <- map["feed"]
type <- map.attributes["type"]
description <- map["description"]
sdImg <- map.attributes["sdImg"]
hdImg <- map.attributes["hdImg"]
}
}
I used XMLMapper/Requests
and converted it to Data
class.
But feed
in my Item
class always nil.
thanks in advance,
Jin
There is any way to catch the parsing errors? I can assume sometimes a xml can't be downloaded but i can't assume the app will crash anytime the xml format is wrong.
Take the following for example:
<foo>
<bar>
<item></item>
<bar>
<bar>
<item></item>
<item></item>
</bar>
</foo>
You have to make a choice to either parse as a single item
or an array [item]
. Both options are not available.
I'm a hobbyist, since XMLMapper 1.6.1 is compatabile with Alamofire 5.2, I was wondering if the Request Subspec is compatible with 5.2 or oly 4.9?
EDIT: podfile has
pod 'Alamofire', '> 5.2',> 1.6.1',
pod 'XMLMapper', '
pod 'XMLMapper/Requests',
as well, when trying with XCode Swift package manager it does the same thing when switching to the enhancements/alamofire5 support tree. Request subspec is not optional
I'm having an issue when using toXMLString()
on objects that are in a Realm DB.
It seems that by calling toXMLString()
on an object that is XMLMappable, the mapping(map: XMLMap)
method for the object is called, which tries to modify the object (even if it is keeping the values the same).
The issue, as far as I know it right now, is that when mapping
is called, the primary key of my object is attempting to be changed, and that causes Realm to crash.
Is there a way to call toXMLString()
without it attempting to modify any of the existing data?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.