Code Monkey home page Code Monkey logo

aexml's People

Contributors

alphatroya avatar andrewtheis avatar banjun avatar bendernk avatar damuellen avatar dmcgloin avatar doomcat55 avatar ewanmellor avatar franklinyu avatar gabors avatar italankin avatar ivensdenner avatar joebayld avatar kiliankoe avatar lightbow avatar michaelforrest avatar nnsnodnb avatar petaren avatar radianttap avatar samritchie avatar sgade avatar stjernegard avatar tadija avatar tlusser avatar vicng avatar wilmot 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  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

aexml's Issues

Use "public" for methods and constructors.

Nearly all methods (including subscriptions and constructors) are not public. Without declaring them as public it is impossible to use that class when using it within an framework.

Write XML overwriting last element

I'm trying to add a new element to an xml doc like so:

 if let document = AEXMLDocument(xmlData: data, error: &error) {
    let attributes = ["location": fishData.location]
    let fish = document["FISHDICT"].addChild(name: "FISH", attributes: attributes)

But this overwrites the last element in the document. Am I doing something wrong?

Why is AEXMLElement.all not nil-able?

It would be nice to be able to use all in a way like that:

for element in parent.all {
}

This will work already, but if there are zero elements, it should get called with self. So I wondered why all isn't nil-able already. Returning self of course makes sense for many functions of this library, I understand, but I don't see any sense in returning self in all too.

I also noticed that there is a small inconsistence about it in the library: AEXMLElement.allWithAttributes is nil-able, while AEXMLElement.all is not.

Can read operations return nilable AEXMLElement?

First, very cool work. Love the simple and super-easy API. Great job!

Perhaps I've not yet appreciated the finer points of Swift, but I'm wondering if the subscript, and last functions/properties can return nilable AEXMLElement (i.e. AEXMLElement?) ?

For my use case, I don't know if a server's XML response will have certain elements. I want to access them if they are present.

Right now, it appears when I do something like this:

 let errorDetail = xmlDocument!.rootElement["errorDetail"]

...I get a dummy empty AEXMLElement, but I really just want nil in this case.

Again, thanks for the great work!

AEXMLParser handles didEndElement Call wrong

An Xml like the following one will result in wrong Value for the Element version:
<Document><version>1.0</version>\n\t</Document>

Current Implementation produces for the Element with Name version value "1.0\n\t" which is wrong.
Expected Value should be "1.0"

Current implementation should be changed to:

func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {
    currentParent = currentParent?.parent
    currentValue = String()
    currentElement = nil
}

XSD Validation

When receiving an XML (for example from a web service) I would prefer to check if the response applies to the defined XSD schema before trying to process it. At the moment there aren't any Swift XML frameworks available which support XSD validation at the moment. Would be a great feature.

Changelog File

Please add a CHANGELOG.md file to make it easier to see what changes with each version. It also gets imported into the CocoaPods directory.

receive Bound value in a conditional binding must be of Optional type

line 223 of AEXML.swift has:

          if let parser = NSXMLParser(data: xmlData) {

Though, it appears as of the most recent Xcode, the following is required:

if let parser = NSXMLParser(data: xmlData) as NSXMLParser! {

Can you please validate my change is correct, and why you are not seeing this issue.

Thanks,
Brian

Attributes

Is there a way to access or enumerate attributes that you don't know the name of? I'd like to be able to load all the attributes of an element into a dictionary.

"Cast from AEXMLElement to unrelated type ___ always fails"

I'm not sure if this is somehow a problem with AEXML or a bug in XCode, or some other weird thing, so pardon me if it has nothing to do with this library.

Somehow, I'm getting an error on a file that doesn't use AEXML that there is a cast from AEXMLElement. If I comment out the #import AEXML line (in a totally unrelated file) then the project builds. Then when I uncomment the import, it builds fine.

I put together a simple sample project to illustrate this.

https://github.com/aaronpk/AEXML_Test

Marshalling data

Hi !

I wonder if there is a way to bind the data with xml.
I mean, create a model class then bind the data by using a xml file.

I know that it's possible on Android, but i'm new to IOS :/

It's possible ?

Or if you have an other way to do it, because my models are complex and I can't bind the data by me self.

Using a variable with .allWithAttributes

Is there a way to pass a variable extract the following? or maybe there's another simple way of doing this.

var theColor = "yellow"
xmlDoc.root["cats"]["cat"].allWithAttributes(["breed" : "Domestic", "color" : "(theColor)"])
or
xmlDoc.root["cats"]["cat"].allWithAttributes(["breed" : "Domestic", "color" : theColor"])

var theInt = 44
xmlDoc.root["event"]["date"].allWithAttributes(["event" : theInt]))
xmlDoc.root["event"]["date"].countWithAttributes(["event" : theInt]))

3 unit tests fail in example project under Xcode 6.1.1 (6A2006)

Without any changes, after downloading latest code, 3 unit tests fail:

testChildrenElements()
testAllElements()
testLastElement()

I was actually trying to debug an issue with Xcode 6.3 Beta, but then I realized that I could not get the tests to run without crashing. However, I had to make 1 change to get code to compile, so I thought maybe my change caused the failure.

However, then I went back to Xcode 6.1.1 and am seeing these 3 test failures.

Will submit separate issue for the Xcode 6.3 beta.

AEXMLElement: severe memory leak due to strong reference cycle

I was tracking a memory leak in an app that I am writing that uses AEXML and finally traced the leak to AEXMLElement. The thing is that once you add children to an AEXMLElement, it does not get deinitialized, even if set to nil.

To reproduce I added a deinit "function" to AEXMLElement, AEXMLDocument and AEXMLParser like

deinit {
    NSLog("Deinit AEXMLElement")
}

Then I ran the following code in an app. The code does not work in PlayGrounds since there is an issue with deinits in PlayGround: http://stackoverflow.com/questions/24021340/memory-leaks-in-the-swift-playground-deinit-not-called-consistently

    var a: AEXMLDocument?
    var b: AEXMLDocument?

    a = AEXMLDocument(version: 1.0, encoding: "UTF8")
    b = AEXMLDocument(version: 1.0, encoding: "UTF8")

    a!.addChild("child", value: "value")

    println("- a -")
    a = nil
    println("- b -")
    b = nil
    println("-----")

When you run the code, you will see something like

- a -
- b -
2014-11-23 17:12:52.654 x-x[12068:1088859] Deinit AEXMLDocument
2014-11-23 17:12:52.655 x-x[12068:1088859] Deinit AEXMLElement
-----

in the console. This shows that only b is deinitialized.

Without digging too far into your code I assume that there is one or more circular reference between a parent element and their children.

Add prependChild feature

Following up with previous feature request, would it be possible to prepend a Child element? I'm currently using my string replacement method to do this.

I know prepending a Child is a rarely used feature, but I would greatly appreciate it.

Thanks again,
atn

__
Update
__

Ended up changing some of my code around, so you can skip on doing this if you want since it would be so rarely used.

Escaping special characters

It seems that AEXML's xmlstring property does not escape characters like "greater than", "less than" and "ampersand". This in turn leads to invalid XML being returned if an element's value contains such a character. Alternatively escaping could also be done when adding an element. Nor sure which is the better way...

AEXMLElement writes attributes unescaped

I am using an old version, but I think this is still in the source - if you set an attribute value to a string with an & in it, it is written unescaped by .xmlString

How parse the tags using AEXML

Hi Team,
Good Day!

Am familiar in XML Parsing using NSXMLParser in Objective-C. Now, am working in Swift I can use the NSXMLParser to parse the XML Response but, I have got suggestions to use third party framework (Library) to parse the xml content easily. I googled and found "AEXML" framework for SWIFT programming. I got confused to access the tags from "AEXMLElement".

I have attached the sample response and my sample code for your reference.

I want to parse the main tag "item" and its sub tags "title", "link", "description", "author", "pubDate". How can I handle this?

Can you please help me to parse the xml files like this?
Looking forward your help. Thank you.

Warm Regards,
Yuvaraj M

screen shot 2015-10-06 at 7 15 38 pm
screen shot 2015-10-06 at 7 15 51 pm

.all! returns an element whose parent is nil

for example in my xml

var x = anelement["attrib"]["attrib"]
returns an AEXMLElement with a good parent

var x = someelements["attrib"]["attrib"].all!
returns some AEXMLElements but each with parent=nil

that cost me a lot of hours today 👎

Unit tests crash in example project under Xcode 6.3 Beta 1 (6D520o)

I know it may not be appropriate to note issues found using Xcode beta, but I thought I would submit this anyway.

The code compiles after a couple minor changes. But it crashes when running the tests.

After some debugging, it looks like this is related to the issue described here:

http://stackoverflow.com/questions/28487142/delegate-methods-not-called-if-implementing-class-is-marked-private

For Swift 1.2, it also looks like the NSXMLParserDelegate function declarations have changed slightly, which may also have been causing the delegate functions to be called.

Unit Tests

Looks like a very nice library, but I would prefer using a library which utilizes unit tests. In case of an XML parses this could have been in done in little number of lines of code (for example).

Unit tests doesn't only ensure that code works as expected, they are also a good reference for new users of a framework.

Parse xml in different level structure

Hi,
I did tweet you on twitter.
According to AEXML, I would like to ask that is it possible to parse different level of xml given by attribute name and attribute value. The problem is there is many different level structures and not the same to every file I want to use.

For example,
Example1.xml
level1
id="01"
id="02"
....level2
....id="03"
....
id="04" (this is in level 1)

Example2.xml
level1
id="01"
..level2
..id="02"
.....level3
.......id="03"
..........
..

Another problem is I would like to get those value in order which will contain many value in the block to the same array structure. It looks weird format, I actually got my own solution by checking every case but sometimes I still miss some case. But I'm not sure if it is better way.

Sorry for my bad English.
Hope this is not confusing you. Thank you so much.

Parsing Element within Another element loses the value of the first Element

I'm parsing some Shakespeare xml files with AEXML (which is working great for me otherwise BTW) when I experience some problems getting the correct values out of elements from the following xml:

SAMPSON Aside to GREGORY Is the law of our side, if I say ay?

I'm running through the SPEECH element (speechElement:AEXMLElement)

for child in speechElement.children {
// when child equals the the first LINE element
child.value // should equal "Is the law of our side, if I say" but is nil
}

The LINE element contains the STAGEDIR element correctly, but loses anything after the STAGEDIR.

I've also moved the STAGEDIR element in the line, like so:
Is the law of Aside to GREGORY our side, if I say
and " our side, if I say" is lost.

I've worked around it by modifying the xml files, but I wanted to file a bug and let you know.

Crash while reading Int value for attributes

Let's modify the first cat on example.xmltest file as follow:

<cat breed="Siberian" color="lightgray" value="99">Tinna</cat>

The attribute valueis added.

Now add the following test to testAttributes() unit test:

XCTAssertEqual(firstCatAttributes["value"] as Int, 99, "Should be able to return INT attribute value.")

A crash then occur: EXC_BAD_ACCESS

While adding this attribute using addAttribute and then reading i, it works fine:

var firstCat = exampleXML.root["cats"]["cat"]
firstCat.addAttribute("value", value: 99)
XCTAssertEqual(firstCat.attributes["value"] as Int, 99, "Should be able to return INT attribute value")

Parsing XML with namespaces

Currently, there is no way to set the XMLParser shouldProcessNamespaces to true. So when accessing an element, the complete tagname with namespace needs to be passed. e.g xml["f:animal"] instead of just xml["animal"]

Subscript Returns Error String as Value of AEXMLElement is Surprising (To Me)

It cramps my style. 😸 It also feels awkward having to type:

let element = elementList["MyElement"]
if element.name != AEXMLElement.errorElementName {
    let string = element["MyString"].stringValue
}

as opposed to something like:

let element = elementList["MyElement"]
let string = element["MyString"].stringValue // I would expect string == ""

because 99% of the time I don't want the string, "element <MyString> not found", because I use stringValue. Was under the assumption that stringValue would return an empty string upon lookup error, not an error string.

This is coming from having used SwiftyJSON. So that is where my expectations are coming from. Feel free to disagree if that's how you feel.

Thoughts?

allWithAttributes returns nil

I discovered some weird behavior of allWithAttributes: it returns nil.

I tested it with following code:

let xmlDoc = try AEXMLDocument(xmlData: result.dataUsingEncoding(NSUTF8StringEncoding)!)
let root = xmlDoc.root
print(root.children[0].attributes)
let xxx = xmlDoc.root.allWithAttributes(["id": "0"])
print(xxx)

And this prints:

["id": "0"]
nil

My xml looks like this:

<gpio>
  <rgb id="0">
    <manually>false</manually>
    <led id="red">true</led>
    <led id="blue">true</led>
    <led id="green">true</led>
    <interactible>true</interactible>
  </rgb>
  <rgb id="1">
    <manually>false</manually>
    <led id="red">true</led>
    <led id="blue">true</led>
    <led id="green">true</led>
    <interactible>true</interactible>
  </rgb>
</gpio>

Do I miss something or is this a misbehavior of allWithAttributes?

Thanks,
Chromo

Remove child feature?

I notice the lack of a remove child feature. Are there any plans for this to incorporated in the future? Or some mostly simply way of doing it (like set an element to nil or something)?

Thanks!

Carthage: Problem during build of watchOS and tvOS

For me it's not possible to perform a carthage update, an error is thrown:

** BUILD FAILED **


The following build commands failed:
    Check dependencies
(1 failure)
A shell task failed with exit code 65:
** BUILD FAILED **


The following build commands failed:
    Check dependencies
(1 failure)

A selective build of iOS and Mac only is working fine.

Swift 2.0 Xcode 7.0 iOS 9

I get the following error:

AEXML-1.3.1/AEXMLExample/ViewController.swift:27:38: Cannot invoke initializer for type 'AEXMLDocument' with an argument list of type '(xmlData: NSData, error: inout NSError?)'

Any suggestions to what may be the issue?

Parsing this format

Could you please help me in parsing this format.
I am not able to correctly parse this kind of format: I want to get the 'text' attributes value of all prop given 'child' index value.
For ex: get all prop's 'text' value given 'child' index 1
root
child index="1" name="child name 1"
prop index="1" text="prop name1" /
prop index="2" text="prop name2" /
/child
child index="2" name="child name 2"
prop index="1" text="prop name1" /
prop index="2" text="prop name2" /
/child
/root

Strange Compiler Bugs?

I'm getting a really strange issue where the compiler is throwing a warning that a previous NSDictionary object is being automatically converted to an AEXMLElement. If I remove AEXML my code compiles fine. The model code in my screenshot below is not using AEXML at all. I've never seen this issue before and I'm wondering if this is a Swift 2.0 XCode 7.0 bug or something.

screen shot 2015-10-01 at 7 53 59 am

Swift 2.0 compatibility

It seems that 1.3.1 is not Swift 2.0-compatible. I fixed the issues (sorry for this pretty unprofessional way of submitting the code, but I'm not used to github...):

snip >>>
//
// AEXML.swift
//
// Copyright (c) 2014 Marko Tadić [email protected] http://tadija.net
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

import Foundation

/**
This is base class for holding XML structure.

You can access its structure by using subscript like this: `element["foo"]["bar"]` would return `<bar></bar>` element from `<element><foo><bar></bar></foo></element>` XML as an `AEXMLElement` object.

*/
public class AEXMLElement: Equatable {

// MARK: Properties

/// Every `AEXMLElement` should have its parent element instead of `AEXMLDocument` which parent is `nil`.
public private(set) weak var parent: AEXMLElement?

/// Child XML elements.
public private(set) var children: [AEXMLElement] = [AEXMLElement]()

/// XML Element name.
public let name: String

/// XML Element value.
public var value: String?

/// XML Element attributes.
public private(set) var attributes: [NSObject : AnyObject]

/// String representation of `value` property (if `value` is `nil` this is empty String).
public var stringValue: String { return value ?? String() }

/// Boolean representation of `value` property (if `value` is "true" or 1 this is `True`, otherwise `False`).
public var boolValue: Bool { return stringValue.lowercaseString == "true" || Int(stringValue) == 1 ? true : false }

/// Integer representation of `value` property (this is **0** if `value` can't be represented as Integer).
public var intValue: Int { return Int(stringValue) ?? 0 }

/// Double representation of `value` property (this is **0.00** if `value` can't be represented as Double).
public var doubleValue: Double { return (stringValue as NSString).doubleValue }

// MARK: Lifecycle

/**
    Designated initializer - `name` is required, others are optional.

    :param: name XML element name.
    :param: value XML element value
    :param: attributes XML element attributes

    :returns: An initialized `AEXMLElement` object.
*/
public init(_ name: String, value: String? = nil, attributes: [NSObject : AnyObject] = [NSObject : AnyObject]()) {
    self.name = name
    self.value = value
    self.attributes = attributes
}

// MARK: XML Read

/// This element name is used when unable to find element.
public class var errorElementName: String { return "AEXMLError" }

// The first element with given name **(AEXMLError element if not exists)**.
public subscript(key: String) -> AEXMLElement {
    if name == AEXMLElement.errorElementName {
        return self
    } else {
        let filtered = children.filter { $0.name == key }
        return filtered.count > 0 ? filtered.first! : AEXMLElement(AEXMLElement.errorElementName, value: "element <\(key)> not found")
    }
}

/// Returns all of the elements with equal name as `self` **(nil if not exists)**.
public var all: [AEXMLElement]? { return parent?.children.filter { $0.name == self.name } }

/// Returns the first element with equal name as `self` **(nil if not exists)**.
public var first: AEXMLElement? { return all?.first }

/// Returns the last element with equal name as `self` **(nil if not exists)**.
public var last: AEXMLElement? { return all?.last }

/// Returns number of all elements with equal name as `self`.
public var count: Int { return all?.count ?? 0 }

/**
    Returns all element with given attributes.

    :param: attributes Array of Keys (`NSObject`) and Value (`AnyObject`) - both must conform to `Equatable` protocol.

    :returns: Optional Array of found XML elements.
*/
public func allWithAttributes <K: NSObject, V: AnyObject where K: Equatable, V: Equatable> (attributes: [K : V]) -> [AEXMLElement]? {
    var found = [AEXMLElement]()
    if let elements = all {
        for element in elements {
            var countAttributes = 0
            for (key, value) in attributes {
                if element.attributes[key] as? V == value {
                    countAttributes++
                }
            }
            if countAttributes == attributes.count {
                found.append(element)
            }
        }
        return found.count > 0 ? found : nil
    } else {
        return nil
    }
}

/**
    Counts elements with given attributes.

    :param: attributes Array of Keys (`NSObject`) and Value (`AnyObject`) - both must conform to `Equatable` protocol.

    :returns: Number of elements.
*/
public func countWithAttributes <K: NSObject, V: AnyObject where K: Equatable, V: Equatable> (attributes: [K : V]) -> Int {
    return allWithAttributes(attributes)?.count ?? 0
}

// MARK: XML Write

/**
    Adds child XML element to `self`.

    :param: child Child XML element to add.

    :returns: Child XML element with `self` as `parent`.
*/
public func addChild(child: AEXMLElement) -> AEXMLElement {
    child.parent = self
    children.append(child)
    return child
}

/**
    Adds child XML element to `self`.

    :param: name Child XML element name.
    :param: value Child XML element value.
    :param: attributes Child XML element attributes.

    :returns: Child XML element with `self` as `parent`.
*/
public func addChild(name name: String, value: String? = nil, attributes: [NSObject : AnyObject] = [NSObject : AnyObject]()) -> AEXMLElement {
    let child = AEXMLElement(name, value: value, attributes: attributes)
    return addChild(child)
}

/**
    Adds given attribute to `self`.

    :param: name Attribute name.
    :param: value Attribute value.
*/
public func addAttribute(name: NSObject, value: AnyObject) {
    attributes[name] = value
}

/**
    Adds given attributes to `self`.

    :param: attributes Dictionary of Attribute names and values.
*/
public func addAttributes(attributes: [NSObject : AnyObject]) {
    for (attributeName, attributeValue) in attributes {
        addAttribute(attributeName, value: attributeValue)
    }
}

/// Removes `self` from `parent` XML element.
public func removeFromParent() {
    parent?.removeChild(self)
}

private func removeChild(child: AEXMLElement) {
    if let childIndex = children.indexOf(child) {
        children.removeAtIndex(childIndex)
    }
}

private var parentsCount: Int {
    var count = 0
    var element = self
    while let parent = element.parent {
        count++
        element = parent
    }
    return count
}

private func indentation(count: Int) -> String {
    var indent = String()
    if count > 0 {
        for i in 0..<count {
            indent += "\t"
        }
    }
    return indent
}

/// Complete hierarchy of `self` and `children` in **XML** formatted String
public var xmlString: String {
    var xml = String()

    // open element
    xml += indentation(parentsCount - 1)
    xml += "<\(name)"

    if attributes.count > 0 {
        // insert attributes
        for (key, value) in attributes {
            xml += " \(key)=\"\(value)\""
        }
    }

    if value == nil && children.count == 0 {
        // close element
        xml += " />"
    } else {
        if children.count > 0 {
            // add children
            xml += ">\n"
            for child in children {
                xml += "\(child.xmlString)\n"
            }
            // add indentation
            xml += indentation(parentsCount - 1)
            xml += "</\(name)>"
        } else {
            // insert string value and close element
            xml += ">\(stringValue)</\(name)>"
        }
    }

    return xml
}

/// Same as `xmlString` but without `\n` and `\t` characters
public var xmlStringCompact: String {
    let chars = NSCharacterSet(charactersInString: "\n\t")

    let parts = xmlString.componentsSeparatedByCharactersInSet(chars)
    let result = "".join(parts)

    return result
}

}

// MARK: -

/**
This class is inherited from AEXMLElement and has a few addons to represent XML Document.

XML Parsing is also done with this object.

*/
public class AEXMLDocument: AEXMLElement {

// MARK: Properties

/// This is only used for XML Document header (default value is 1.0).
public let version: Double

/// This is only used for XML Document header (default value is "utf-8").
public let encoding: String

/// This is only used for XML Document header (default value is "no").
public let standalone: String

/// Root (the first child element) element of XML Document **(AEXMLError element if not exists)**.
public var root: AEXMLElement { return children.count == 1 ? children.first! : AEXMLElement(AEXMLElement.errorElementName, value: "XML Document must have root element.") }

// MARK: Lifecycle

/**
    Designated initializer - Creates and returns XML Document object.

    :param: version Version value for XML Document header (defaults to 1.0).
    :param: encoding Encoding value for XML Document header (defaults to "utf-8").
    :param: standalone Standalone value for XML Document header (defaults to "no").
    :param: root Root XML element for XML Document (defaults to `nil`).

    :returns: An initialized XML Document object.
*/
public init(version: Double = 1.0, encoding: String = "utf-8", standalone: String = "no", root: AEXMLElement? = nil) {
    // set document properties
    self.version = version
    self.encoding = encoding
    self.standalone = standalone

    // init super with default name
    super.init("AEXMLDocument")

    // document has no parent element
    parent = nil

    // add root element to document (if any)
    if let rootElement = root {
        addChild(rootElement)
    }
}

/**
    Convenience initializer - used for parsing XML data (by calling `readXMLData:` internally).

    :param: version Version value for XML Document header (defaults to 1.0).
    :param: encoding Encoding value for XML Document header (defaults to "utf-8").
    :param: standalone Standalone value for XML Document header (defaults to "no").
    :param: xmlData XML data to parse.
    :param: error If there is an error reading in the data, upon return contains an `NSError` object that describes the problem.

    :returns: An initialized XML Document object containing the parsed data. Returns `nil` if the data could not be parsed.
*/
public convenience init?(version: Double = 1.0, encoding: String = "utf-8", standalone: String = "no", xmlData: NSData, inout error: NSError?) {
    self.init(version: version, encoding: encoding, standalone: standalone)
    if let parseError = readXMLData(xmlData) {
        error = parseError
        return nil
    }
}

// MARK: Read XML

/**
    Creates instance of `AEXMLParser` (private class which is simple wrapper around `NSXMLParser`) and starts parsing the given XML data.

    :param: data XML which should be parsed.

    :returns: `NSError` if parsing is not successfull, otherwise `nil`.
*/
public func readXMLData(data: NSData) -> NSError? {
    children.removeAll(keepCapacity: false)
    let xmlParser = AEXMLParser(xmlDocument: self, xmlData: data)
    return xmlParser.tryParsing() ?? nil
}

// MARK: Override

/// Override of `xmlString` property of `AEXMLElement` - it just inserts XML Document header at the beginning.
public override var xmlString: String {
    var xml =  "<?xml version=\"\(version)\" encoding=\"\(encoding)\" standalone=\"\(standalone)\"?>\n"
    for child in children {
        xml += child.xmlString
    }
    return xml
}

}

// MARK: -

class AEXMLParser: NSObject, NSXMLParserDelegate {

// MARK: Properties

let xmlDocument: AEXMLDocument
let xmlData: NSData

var currentParent: AEXMLElement?
var currentElement: AEXMLElement?
var currentValue = String()
var parseError: NSError?

// MARK: Lifecycle

init(xmlDocument: AEXMLDocument, xmlData: NSData) {
    self.xmlDocument = xmlDocument
    self.xmlData = xmlData
    currentParent = xmlDocument
    super.init()
}

// MARK: XML Parse

func tryParsing() -> NSError? {
    var success = false
    let parser = NSXMLParser(data: xmlData)
    parser.delegate = self
    success = parser.parse()
    return success ? nil : parseError
}

// MARK: NSXMLParserDelegate

func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {

    currentValue = String()
    currentElement = currentParent?.addChild(name: elementName, attributes: attributeDict)
    currentParent = currentElement

}

func parser(parser: NSXMLParser, foundCharacters string: String?) {
    currentValue += string ?? String()
    let newValue = currentValue.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    currentElement?.value = newValue == String() ? nil : newValue
}

func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
    currentParent = currentParent?.parent
    currentElement = nil
}

func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
    self.parseError = parseError
}

}

// MARK: - Equatable

/**
Implementation of Equatable protocol for AEXMLElement.
*/
public func ==(lhs: AEXMLElement, rhs: AEXMLElement) -> Bool {
if lhs.name != rhs.name { return false }
if lhs.value != rhs.value { return false }
if lhs.parent != rhs.parent { return false }
if lhs.children != rhs.children { return false }
if lhs.attributes != rhs.attributes { return false }
return true
}

/**
Implementation of Equatable protocol for AEXMLElement.
*/
public func !=(lhs: [NSObject: AnyObject], rhs: [NSObject: AnyObject]) -> Bool {
for (key, lhsValue) in lhs {
if let rhsValue: AnyObject = rhs[key] {
if !(lhsValue === rhsValue) { return true }
} else { return true }
}
return false
}
<<<

Differentiate <error> and element <error> not found

let dataString1 = "<?xml version='1.0' encoding='utf-8'?><results><error>No entry for today</error></results>"
let dataString2 = "<?xml version='1.0' encoding='utf-8'?><results><entry>Some entry</entry></results>"

let data = dataString1.dataUsingEncoding(NSUTF8StringEncoding)

var xmlError: NSError?
if let xmlDoc = AEXMLDocument(xmlData: data!, error: &xmlError) {
    let errorTag = xmlDoc.root["error"]

    // always going to be true
    if xmlDoc.root["error"].name == "error" {
        let e = NSError(domain: "...", code: 101, userInfo: [NSLocalizedDescriptionKey: errorTag.stringValue])
        return onFailure(error: e)
    }

    // never gets to here...
}

When dataString1 is used, the code above behaves as expected. <error> tag is determined as "error" and handled as such.

When dataString2 is used, the above fails to find <error> tag in the data and the check omits element "error" not found "error".

There seems to be no way to distinguish between actual <error> tag and missing <error> tag unless I just make an exception for stringValue == element <error> not found.

I think that existence of <error> should not be handled inside AEXML. Or at least not be the same kind of error as is when xmlDoc.root["error"].name returns "error".

Checking for existence of <error> tag should be with a != instead of ==.

Should allow you to do xmlDoc.root["error"].name != "error" instead of the current xmlDoc.root["error"].name == "error".

parse xml

How to parse xml like this

<users>
   <user>
    <name>
    <age>
  </user>
</users>

i tried

for user in xmlDoc.root["users"]["user"].all! {
            for child in user.children{
                switch(child.name){
                case "name":

                    break
                case "age":

                    break
                default:
                    break
                }
            }
        }

but i dont know if this is the best way to do it.

AEXML crashes in XCode 6.3.1

Hi, Before upgrading to latest version of xcode 6.3.1. AEXML was working perfectly. But after upgrade it is crashing. below is the error message.

Optional("XML Document must have root element.")
nil
fatal error: Array index out of range

please fix this issue as soon as possible because my project depends on this.

Thanks & Regards
Sayeed.

creating an array struct

Can I create an array struct for all child element with a specific value? Need to choose

cats->cat->name: Tinna

the problem is my xml file has no any breeds, need to check values.

Parsing Element within Another element loses the value of the first Element

I'm submitting a new bug related to #66. I responded to your response, but I didn't see anything after that.

Below is my response:

Sorry, I missed escaping opening the in the previous comment.

Below is the XML that is valid and AEXML was not correctly taking in.

SAMPSON Aside to GREGORY Is the law of our side, if I say ay?

Root Element Error

In the old version everything worked fine but now I have this problem:
XML Document must have root element.

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.