Swxmlhash Parse Data Object

SWXMLHash parse Data object

According to SWXMLHash

public func parse(_ xml: String) -> XMLIndexer {
guard let data = xml.data(using: options.encoding) else {
return .xmlError(.encoding)
}
return parse(data)
}

public func parse(_ data: Data) -> XMLIndexer {
let parser: SimpleXmlParser = options.shouldProcessLazily
? LazyXMLParser(options)
: FullXMLParser(options)
return parser.parse(data)
}

Whereas you give a String or a Data object, internally it will parse a Data object doing a conversion if needed.
It's a safe way of coding, this way all initialization methods pass through the same one, and fixing it fix all the different initialization.

So it should work.

Your issue is that you file is a string representation of HexData, not a RawHexData file.

The solution is to put in that file the XML String instead.

The Data(contentsOf: fileURL, options: .mappedIfSafe) will convert that XML String into a Hex representation of it.
And then it will work.

Unable to parse XML from Webservice using SWXMLHash

OK. I have solved the problem. The issue was with the XML file i receive from the server. It looks like it is UTF-8 format, but the document says it is UTF-16. So, I now convert the data object received into a UTF-8 NSString, and then cast that into a String! Please see the code below:

    let baseUrl = "http://apps.hha.co.uk/mis/Api/getlivesensors.aspx?key=6fb21537-fb4e-4fe4-b07a-d8d68567c9d1"
var request = URLRequest(url: NSURL(string: baseUrl)! as URL)
let session = URLSession.shared
request.httpMethod = "GET"

let task = session.dataTask(with: request as URLRequest) {
(data, response, error) in

if data == nil {
print("dataTaskWithRequest error: \(error)")
return
}

let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)?.replacingOccurrences(of: "utf-16", with: "utf-8")

let xml = SWXMLHash.parse(dataString! as String)
//let xml = SWXMLHash.parse(dataString!)

if (xml["Sensors"]["Sensor"][0]["Name"].element?.text) != nil
{
self.sensors.add(xml["Sensors"]["Sensor"][0]["Name"].element?.text as Any)
}

DispatchQueue.main.async(execute : {
print(self.sensors)
})

}
task.resume()
// but obviously don't try to use it here here

Deserialisation error with SWXMLHash

You're almost there, just one small mistype... instead of XMLElementDeserializable, you should use XMLIndexerDeserializable.

The below works for me in a Playground:

import SWXMLHash

let xmlData = "<Root>" +
"<SomeData>Some value</SomeData>" +
" <ClientInfo>" +
" <Client>MD</Client>" +
" <Name>Massive Dynamic</Name>" +
" </ClientInfo>" +
"</Root>"

let xml = SWXMLHash.parse(xmlData)

struct ClientInfo : XMLIndexerDeserializable {
let Client: String
let Name: String

static func deserialize(_ node: XMLIndexer) throws -> ClientInfo {
return try ClientInfo(
Client: node["Client"].value(),
Name: node["Name"].value()
)
}
}

let info: ClientInfo? = try? xml.children[0]["ClientInfo"].value()

The distinction between those two gets a little confusing and it definitely needs to be improved in the library. The gist is that XMLElementDeserializable is for standalone types (e.g. strings, ints, dates, etc.) that don't have children nodes.

Can't return value parsing XML using SWXMLHash in Swift

Firt thing: you forgot to include ["product"] at the beginning of your query.

Then your last subscripting with [type="probability_of_precipitation"] wasn't using the right syntax.

Here's two different ways of getting your value.

1- By index:

let precipForecast = xml["product"]["forecast"]["area"][2]["forecast-period"][0]["text"][1].element?.text

2- By attributes, with .withAttr. In your case, for "type":

do {
let precipForecast = try xml["product"]["forecast"]["area"][2]["forecast-period"][0]["text"].withAttr("type", "probability_of_precipitation").element?.text
} catch {
print(error)
}

or if your want an Optional:

let precipForecast = try? xml["product"]["forecast"]["area"][2]["forecast-period"][0]["text"].withAttr("type", "probability_of_precipitation").element?.text

Good parser to parse large XML file and handling the parsed data in Swift

If:

  • This data does not always need to be updated, only on occasion.

  • Core data can scale effectively to a very large number of small entries.

Then:

  • Use whichever XMLParser is fastest with large data sets.

  • Parse the downloaded data, and store the parsed data into Core Data (possibly create new entries per XML key:value pair).

  • After the initial download of the XML file, only check the status code on subsequent accesses (304 means that nothing has changed).

  • When populating the table, you can use Core Data to access the individual properties without loading the whole file into memory.

Any easier way to convert XML to Plist?

You could make your Item conform to Encodable

  struct Item: XMLIndexerDeserializable, Encodable {
let name: String
let enabled: String
let schema_ver: String
let ver: String
let actions: Actions // this property would have to be Encodable as well
}

struct Actions: Encodable {...}

Then you don't have to use a dictionary, pretty much same as you had it.

func convertToPlist(item: Item) {
let encoder = PropertyListEncoder()
encoder.outputFormat = .binary
do {
let data = try encoder.encode(item)
let fileURL = URL(<where you want to save plist>)
try data.write(to: fileURL)
} catch {
// Handle error
print(error)
}
}

Not sure on making the output smaller. PropertyListEncoder has a few different output options. .binary might decrease the size a bit.

encoder.outputFormat = .binary


Related Topics



Leave a reply



Submit