Giter Club home page Giter Club logo

xmlparsing's Introduction

XMLParsing

Encoder & Decoder for XML using Swift's codable protocol.

Installation

CocoaPods

CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. You can install it with the following command:

$ gem install cocoapods

Navigate to the project directory and create a podfile with the following command:

$ pod install

Inside of your Podfile, specify the XMLParsing pod:

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'YourApp' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Test
  pod 'XMLParsing', :git => 'https://github.com/ShawnMoore/XMLParsing.git'

end

Then, run the following command:

$ pod install

Open the the xcworkspace file that was created. This should be the file you use everyday to create your app, instead of the xcodeproj file.

Carthage

Carthage is a dependency manager that builds your dependencies and provides you with binary frameworks.

Carthage can be installed with Homebrew using the following command:

$ brew update
$ brew install carthage

Inside of your Cartfile, specify XMLParsing:

github "ShawmMoore/XMLParsing"

Then, run the following command to build the framework:

$ carthage update

Drag the built framework into your Xcode project.

Swift Package Manager

Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

Once you have your Swift package set up, adding XMLParsing as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/ShawnMoore/XMLParsing.git", from: "0.0.3")
]

Example

import XMLParsing

let xmlStr = """
<note>
    <to>Bob</to>
    <from>Jane</from>
    <heading>Reminder</heading>
    <body>Don't forget to use XMLParsing!</body>
</note>
"""
    
struct Note: Codable {
    var to: String
    var from: String
    var heading: String
    var body: String
}

guard let data = xmlStr.data(using: .utf8) else { return }

let note = try? XMLDecoder().decode(Note.self, from: data)

let returnData = try? XMLEncoder().encode(note, withRootKey: "note")

xmlparsing's People

Contributors

dingwilson avatar shawnmoore avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xmlparsing's Issues

Error 401 with post request !

Hi ,

i'm testing the Library with https://openweathermap.org

the API link is
"http://api.openweathermap.org/data/2.5/weather"

my model is

struct weather:Codable {
    let q : String
    let appid : String
    let mode : String
}

and the request is

        var request = URLRequest(url: URL(string: "http://api.openweathermap.org/data/2.5/weather")!)
        request.httpMethod = "POST"
        
        let post2 = weather(q: "london", appid: "f4be702b940e5073d765cb2473f0b31b", mode: "xml")


        do{
           
            let body = try XMLEncoder().encode(post2, withRootKey: "current")

            request.httpBody = body
            
        } catch{}
 
        let session = URLSession.shared
        let task = session.dataTask(with: request) { data, response, error in
            if error != nil {
                print("error: \(String(describing: error))")// Handle error…
                return
            }

            guard let data = data else {return }
  
            print("response: \(response)")
           print("data: \(data)")
       

    }
        task.resume()

I don't know where is the problem !
I always get error code 401

but on PostMan it working fine

Issue parsing XML with attributes and a string value

<SomeElement SomeAttribute="value">some string value</SomeElement> ends up only decoding as a string. I would expect to be able to have a struct like:

struct SomeElement: Codable {
    let value: String
    let attribute: String
    enum CodingKeys: String, CodingKey {
        case value = "#text"
        case attribute = "SomeAttribute"
    }
}

I receive the following error:
"Expected to decode Array<Any> but found a string/data instead."

My xml is structured like this:

<ParentElement>
   <SomeElement SomeAttribute="value">some string value</SomeElement>
   <SomeElement SomeAttribute="value">some other string value</SomeElement>
</ParentElement>

And my struct is:

struct ParentElement: Codable {
   let someElements: [SomeElement]

   enum CodingKeys: String, CodingKey {
        case someElements = "SomeElement"
    }
}

struct SomeElement: Codable {
   let someAttribute: String
   let value: String

   enum CodingKeys: String, CodingKey {
        case someAttribute = "SomeAttribute"
        case value = "??"
    }
}

_XMLElement `flatten()` overwrites values

I'm trying to parse a XML feed which provides a HTML and a String version for the same key. flatten() is overwriting the existing value, instead of appending it into an array or keeping the first value (although, someone else might want the last value), it should be set to an array.

Incorrect unboxing of integer hex values

Thank you very much for your work.

I think I have found a little bug, decoding a hexadecimal value can be rounded, for example 0x400ff040 returns 0x400ff000.

The bug is in the inbox functions for integer types, such as internal func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? function.

If valueencodes an hex integer number, it is internally converted in a float number by the instruction let number = NSNumber(value: value): just print number for checking.

So I have modified the function as :

internal func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? {
  if let string = value as? String {
    if string.starts (with: "0x"), let uint32 = UInt32 (string.dropFirst (2), radix: 16) {
      return uint32
    }else if let uint32 = UInt32 (string) { // Decimal
      return uint32
    }else{
      throw DecodingError._typeMismatch (at: self.codingPath, expectation: type, reality: value)
    }
  }else{
    return nil
  }
}

Best regards,

Pierre Molinaro

Issue parsing XML file in key value structure

Hi, I'm trying to parse an XML file that has a key value structure but it doesn't look like it's supported. You can see the XML file using the link and the model can be seen below. How can I parse the file below using this library?

Link to XML file: http://mobile.public.ec2.nytimes.com.s3-website-us-east-1.amazonaws.com/candidates/content/v1/articles.plist

struct Articles: Codable {
    let article: [Dict]
    
    enum CodingKeys: String, CodingKey {
        case article = "dict"
    }
    
}

struct Dict: Codable {
    let title: String
    let body: String
    let images: [Images]
}

struct Images: Codable {
    let height: Int
    let url: String
    
}

Issue parsing Custom XML Structure

Hi!

I've this XML Structure:

<xml>
<response>
    <data>
        <modules>
            <module>
                <id>1</id>
            </module>
        </modules>
    </data>
    <result_id>1</result_id>
    <result_text></result_text>
    <timeout>207</timeout>
</response>
</xml>

And my code to Parse this:

struct ModuleResponse: Codable {
    let result_id: Int?
    let result_text: String?
    let timeout: Int
    let modules: [Module]?

    enum CodingKeys: String, CodingKey {
        case result_text = "result_text"
        case result_id = "result_id"
        case timeout = "timeout"
        case modules = "modules"
    }
}

struct Module: Codable {
    let id: Int
}

Only get timeout value, others No value associated with key CodingKeys.....

Thnks a lot!

Encode attributes

HI

I played with your library a bit, and it is really a great job! However there is a huge technical gap in the decoding part: We are losing the information that the property was an attribute or an element. For decoding it works well, but it can not save the information in the same way.
Example:

struct Test {
var name: String?
var information: String?
}

Input: 
<test name="tag">
<information>tag information</information>
</test>

Output: 
<test>
<name>tag</name>
<information>tag information</information>
</test>

Issue with MusicXML file

I am new to XML decoding and have a issue decoding this part of a musicXML file with your decoder.

Issues:

(Item 1 I figured out what I was doing wrong.)
// 1. Attributes on measure element (number="4" width="267.83") are missing - or I don't understand
// how to setup the structure to return them - using the XMLParser the attributes show up.

2. <rest/> doesn't get detected/decoded - or I don't know how to differentiate between this and a missing "rest" element since both show in my structure as nil.

(grr - item 3 was a typo on me.)
//3. barline element bar-style is not decoded and/or returns nil and the barline attribute (direction) is //not decoded or I do not know how to setup my structure.

Here is a print of that part of the score struct:

xmlTest.Note(rest: nil, pitch: nil, duration: Optional(1), voice: Optional(1), type: Optional("quarter"), stem: nil)]), barlne: nil)

(fragment of musicXML file)

         <measure number="4" width="267.83">
           <note>
                <rest/>
                <duration>1</duration>
                <voice>1</voice>
                <type>quarter</type>
            </note>
            <barline location="right">
                <bar-style>light-heavy</bar-style>
                <repeat direction="backward"/>
            </barline>
        </measure>

...

(structs to receive decoded data)

struct Measure: Codable  {
    var number: Int?
    var width: Float?
    var attributes: Attributes?
    var note: [Note]?
    var barline: Barline?
}

struct Attributes: Codable  {
    var divisions: Int?
    var key: Key?
    var time: Time?
    var clef: Clef?
}

struct Note: Codable  {
    var rest: String?
    var pitch: Pitch?
    var duration: Int?
    var voice: Int?
    var type: String?
    var stem: String?
}

struct Barline: Codable  {
    var barStyle: String?
    var repeatType: String?
    
    enum CodingKeys: String, CodingKey {
        case barStyle = "bar-style"
        case repeatType = "repeat"
    }
}

And here is the code fragment for the decoding:

            let decoder = XMLDecoder()
            
            let formatter: DateFormatter = {
                let formatter = DateFormatter()
                formatter.dateFormat = "yyyy-MM-dd"
                return formatter
            }()
            
            decoder.dateDecodingStrategy = .formatted(formatter)
            
            do {
                let score = try decoder.decode(Score.self, from: data)
                print("Score: \(score)")
            } catch {
                print(error)
            }

Root node key / value ignored on `flatten`

I'm getting back XML with just a <String>...</string> value, so the key / value of the root node is correct but flatten only takes the attributes and flattens the children, but doesn't add the key / value of the current node.

Parser is unable to parse continuous set of String

Hi Team,

I am trying to parse below simple json file
"PublicLowRiskMediumRiskHighRisk"
Below struct I have defined for it
struct Value: Decodable {
var name: [String]?
enum CodingKeys: String, CodingKey {
case name = "Name"
}
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try? values.decode([String].self, forKey: .name)
}
}

but the parser failed to decode the above xml file.

I have debugged the code and found out that node.flatten() code in line number 256 , in class _XMLStackParser is returning only final value from the child array. So ultimately I am getting value of last node

HighRisk

Please fix the issue as early as possible.

Thanks,
Remya.

Using in iOS project does not work

I am having problems using this framework in an iOS project.
It first claimed that this module was created for macos 10.10 target. I cloned the project and made the changes relevant changes: Added deployment target for iphoneos but that didnt work.

I tried to use cocoapods to integrate it in my project but I get:

[!] CocoaPods could not find compatible versions for pod "XMLParsing":
In Podfile:
XMLParsing (from https://github.com/ShawnMoore/XMLParsing.git)

Specs satisfying the XMLParsing (from https://github.com/ShawnMoore/XMLParsing.git`)` dependency were found, but they required a higher minimum deployment target.

Did anyone else had this problem?

Create tag 0.0.1

Thanks for merging my PR! 👍 For CocoaPods to work, there needs to be a tag to clone. Please create a tag 0.0.1. Thanks!

PS: After doing so, please push the podspec. If you need help with that, feel free to let me know! I would be more than happy to help out in any way possible. :)

Parsing HTML inside XML

There is XML that I am looking at that has an element with HTML inside it. I am not sure how to get it. Do I use String, or do I need to create a HTML struct?

Class vs Struct Decoding

Let's say I have this simple XML:

let sample = """
            <wrapper>
                <firstName>Peter</firstName>
                <lastName>Ent</lastName>
                <address>Atlanta, GA</address>
            </wrapper>
        """

And I wish to decode it into the following Swift classes:

class MyBase: Codable {
    var firstName: String?
    var lastName: String?
}

class MyAddress: MyBase {
    var address: String?
}

I've set up set up a function like this:

func decodeMessage<T: Codable>(_ data: Data) -> T? {
        let response = try? XMLDecoder().decode(T.self, from: data)
        return response
}

When I call it as follows:

let dataIn = sample.data(using: .utf8)!
if let person = parser.decodeMessage(dataIn) as MyAddress? {
        print("Decode works: \(String(describing: person.firstName)) \(String(describing: person.lastName)) at \(String(describing: person.address))")
}

It only parses the MyBase class (firstName and lastName), ignoring address in the MyAddress class. Why is that?

I can work around this by using CodingKeys and implementing encode and decode functions, but I shouldn't have to, right?

Or am I missing something?

Update to support tvOS

[!] The platform of the target (tvOS 13) is not compatible with XMLParsing (0.0.2), which does not support tvOS.

keyDecodingStrategy is not implemented

JSONDecoder in swift has a property called keyDecodingStrategy which is really really useful is many cases, is there a chance that we get something like that in XMLDecoder?

Parsing array of same keyed Items

Hello!

Is there a way to parse something such as

<TextLines>
<Text>Line1</Text>
<Text>Line2</Text>
<Text>Line3</Text>
<Text>Line4</Text>
<Text>Line5</Text>
</TextLines>

As it gets recognized as a dictionary, only the last one is returned when using something like this:

public struct TextLine: Decodable {
  public let text: String

  enum CodingKeys: String, CodingKey {
    case text = "Text"
  }
}

public struct Document: Decodable {
  public let textLines: [TextLine]

  enum CodingKeys: String, CodingKey {
    case textLines = "TextLines"
  }
}

Which isn't even a correct representation of the XML. I think it should be something like this if I am correct but this fails:

public struct TextLines: Decodable {
  public let text: [String]

  enum CodingKeys: String, CodingKey {
    case text = "Text"
  }
}

public struct Document: Decodable {
  public let textLines: TextLines

  enum CodingKeys: String, CodingKey {
    case textLines = "TextLines"
  }
}

Any suggestions?

How to decode empty array?

I have server response like this

<?xml version="1.0" encoding="UTF-8"?>
<add-ons type="array"/>

I'm trying to decode it as [AddOn]

public final class AddOn: BraintreeContent {
    public var amount: Double?
    public var currentBillingCycle: Int?
    public var description: String
}

but I'm getting error DecodingError.keyNotFound: Value required for key 'Index 0.description'.
Is there any way to decode it properly into empty array or this framework just doesn't support decoding empty arrays?

Incorrect nested array decoding

I have XML like this

<search-results>
    <page-size type="integer">50</page-size>
    <ids type="array">
        <item>6yrscx</item>
        <item>88kw7x</item>
    </ids>
</search-results>

trying to decode it into this struct

struct Response: Codable {
    let pageSize: Int
    struct Item: Codable {
        let item: String?
        let type: String
    }
    let ids: [Item]
    
    private enum CodingKeys : String, CodingKey {
        case pageSize = "page-size", ids
    }
}

but ids.count is always 1 and contains only last 88kw7x value

in XMLDecoder.swift on line #153 I'm printing print("topLevel: \(topLevel)") and it always showing me ["page-size": "50", "ids": ["item": "88kw7x", "type": "array"]]

@ShawnMoore Is there a way to decode ids correctly using this lib or it's a bug?

escapedCharacterSet missing a semi-colon in ampersand case

XMLStackParser.swift

static let escapedCharacterSet = [("&", "&amp"), ("<", "&lt;"), (">", "&gt;"), ( "'", "&apos;"), ("\"", "&quot;")]

should be

static let escapedCharacterSet = [("&", "&amp;"), ("<", "&lt;"), (">", "&gt;"), ( "'", "&apos;"), ("\"", "&quot;")]

Encoder: Support for XML namespaces

I'd like to use this library for communicating with SOAP web-services. For those, you often encounter namespaces in SOAP requests, e.g.:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://xxxx.com/ipcp/services/v2/common/types" xmlns:par="http://xxxx.com/ipcp/services/v2/reservationWebService/parameters" xmlns:typ1="http://xxxx.com/ipcp/services/v2/reservationWebService/types">
    <soapenv:Header>
        <typ:IpcpHeader>
            <typ:tenantKey>FOO</typ:tenantKey>
            <typ:userName>BAR</typ:userName>
            <typ:password>BAZ</typ:password>
        </typ:IpcpHeader>
    </soapenv:Header>
    <soapenv:Body>
        <par:CreateReservation>
            <par:areaId>302</par:areaId>
            <par:productId>654</par:productId>
            <par:customerId>2852</par:customerId>
            <par:accessInformations>
                <typ:accessTypeId>1</typ:accessTypeId>
                <typ:accessTypeKey></typ:accessTypeKey>
                <typ:accessInformationId></typ:accessInformationId>
                <typ:encodedValue>newnew08234</typ:encodedValue>
                <typ:displayedValue>newnew08234</typ:displayedValue>
            </par:accessInformations>
            <par:accessInformations>
                <typ:accessTypeId>51</typ:accessTypeId>
                <typ:accessInformationId>6004</typ:accessInformationId>
                <typ:encodedValue>830394</typ:encodedValue>
                <typ:displayedValue>830394</typ:displayedValue>
            </par:accessInformations>
            <par:startTime>2019-11-06T12:41:00.000+01:00</par:startTime>
            <par:endTime>2019-12-06T12:41:00.000+01:00</par:endTime>
        </par:CreateReservation>
    </soapenv:Body>
</soapenv:Envelope>

What's the best way to create an XML-document like this one with XMLParsing? It would be nice if we could enhance a struct to feature an optional qualifiedNamespace field that contains the namespace prefix (which would then be automatically inserted by the encoder) and the local name (URI, which could either be automatically scanned and inserted into the envelope, or manually).

Add License

Hi @ShawnMoore, this project is very useful, however it does not have any sort of open source license applied to it, which makes many unable to use it. Can you please specify a usage license?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.