Coder Social home page Coder Social logo

xmldictionary's Introduction


WARNING: THIS PROJECT IS DEPRECATED

It will not receive any future updates or bug fixes. If you are using it, please migrate to another solution.


Purpose

XMLDictionary is a class designed to simplify parsing and generating of XML on iOS and Mac OS. XMLDictionary is built on top of the NSXMLParser classes, but behaves more like a DOM-style parser rather than SAX parser, in that it creates a tree of objects rather than generating events at the start and end of each node.

Unlike other DOM parsers, XMLDictionary does not attempt to replicate all of the nuances of the XML standard such as the ability to nest tags within text. If you need to represent something like an HTML document then XMLDictionary won't work for you. If you want to use XML as a data interchange format for passing nested data structures then XMLDictionary may well provide a simpler solution than other DOM-based parsers.

Supported OS & SDK Versions

  • Supported build target - iOS 10.2 / Mac OS 10.12 (Xcode 8.2, Apple LLVM compiler 8.0)
  • Earliest supported deployment target - iOS 8.0 / Mac OS 10.10
  • Earliest compatible deployment target - iOS 4.3 / Mac OS 10.6

NOTE: 'Supported' means that the library has been tested with this version. 'Compatible' means that the library should work on this OS version (i.e. it doesn't rely on any unavailable SDK features) but is no longer being tested for compatibility and may require tweaking or bug fixes to run correctly.

ARC Compatibility

As of version 1.1, XMLDictionary requires ARC. If you wish to use XMLDictionary in a non-ARC project, just add the -fobjc-arc compiler flag to the XMLDictionary.m class. To do this, go to the Build Phases tab in your target settings, open the Compile Sources group, double-click XMLDictionary.m in the list and type -fobjc-arc into the popover.

If you wish to convert your whole project to ARC, comment out the #error line in XMLDictionary.m, then run the Edit > Refactor > Convert to Objective-C ARC... tool in Xcode and make sure all files that you wish to use ARC for (including XMLDictionary.m) are checked.

Thread Safety

XMLDictionary's methods should all be thread safe. It is safe to use multiple XMLDictionaryParsers concurrently on different threads, but it is not safe to call the same parser concurrently on multiple threads.

Installation

To use the XMLDictionary in an app, just drag the class files into your project.

XMLDictionaryParser

The XMLDictionaryParser class is responsible for parsing an XML file into a dictionary. You don't normally need to use this class explicitly as you can just use the utility methods added to NSDictionary, however it can be useful if you want to modify the default parser settings.

You can create new instances of XMLDictionaryParser if you need to use multiple different settings for different dictionaries. Once you have created an XMLDictionaryParser you can use the following methods to parse XML files using that specific parser instance:

- (NSDictionary *)dictionaryWithData:(NSData *)data;
- (NSDictionary *)dictionaryWithString:(NSString *)string;
- (NSDictionary *)dictionaryWithFile:(NSString *)path;
- (NSDictionary *)dictionaryWithParser:(NSXMLParser *)parser;

Alternatively, you can simply modify the settings of [XMLDictionaryParser sharedInstance] to affect the settings for all dictionaries parsed subsequently using the NSDictionary category extension methods.

Use the following properties to tweak the parsing behaviour:

@property (nonatomic, assign) BOOL collapseTextNodes;

If YES (the default value), tags that contain only text and have no children, attributes or comments will be collapsed into a single string object, simplifying traversal of the object tree.

@property (nonatomic, assign) BOOL stripEmptyNodes;

If YES (the default value), tags that are empty (have no children, attributes, text or comments) will be stripped.

@property (nonatomic, assign) BOOL trimWhiteSpace;

If YES (the default value), leading and trailing white space will be trimmed from text nodes, and text nodes containing only white space will be omitted from the dictionary.

@property (nonatomic, assign) BOOL alwaysUseArrays;

If YES, the every child node will be represented as an array, even if there is only one of them. This simplifies the logic needed to cope with properties that may be duplicated because you don't need to use [value isKindOfClass:[NSArray class]] to check the for the singular case. Defaults to NO.

@property (nonatomic, assign) BOOL preserveComments;

If YES, XML comments will be grouped into an array under the key __comments and can be accessed via the comments method. Defaults to NO.

@property (nonatomic, assign) XMLDictionaryAttributesMode attributesMode;

This property controls how XML attributes are handled. The default is XMLDictionaryAttributesModePrefixed meaning that attributes will be included in the dictionary, with an _ (underscore) prefix to avoid namespace collisions. Alternative values are XMLDictionaryAttributesModeDictionary, which will place all the attributes in a separate dictionary, XMLDictionaryAttributesModeUnprefixed, which includes the attributes without prefix (which may cause collisions with nodes) and XMLDictionaryAttributesModeDiscard, which will strip the attributes.

@property (nonatomic, assign) XMLDictionaryNodeNameMode nodeNameMode;

This property controls how the node name is handled. The default value is XMLDictionaryNodeNameModeRootOnly, meaning that the node name will only be included in the root dictionary (the names for the children can be inferred from the dictionary keys, but the nodeName method won't work for anything except the root node). Alternative values are XMLDictionaryNodeNameModeAlways, meaning that the node name will be included in the dictionary with the key __name (and can be accessed using the nodeName) method, or XMLDictionaryNodeNameModeNever which will never include the `__name' key.

Category Methods

XMLDictionary extends NSDictionary with the following methods:

  • (NSDictionary *)dictionaryWithXMLParser:(NSParser *)parser;

Create a new NSDictionary object from an existing NSXMLParser. Useful if fetching data through AFNetworking.

+ (NSDictionary *)dictionaryWithXMLData:(NSData *)data;

Create a new NSDictionary object from XML-encoded data.

+ (NSDictionary *)dictionaryWithXMLString:(NSString *)string;

Create a new NSDictionary object from XML-encoded string.

+ (NSDictionary *)dictionaryWithXMLFile:(NSString *)path;

Create a new NSDictionary object from and XML-encoded file.

- (NSString *)attributeForKey:(NSString *)key;

Get the XML attribute for a given key (key name should not include prefix).

- (NSDictionary *)attributes;

Get a dictionary of all XML attributes for a given node's dictionary. If the node has no attributes then this will return nil.

- (NSDictionary *)childNodes;

Get a dictionary of all child nodes for a given node's dictionary. If multiple nodes have the same name they will be grouped into an array. If the node has no children then this will return nil.

- (NSArray *)comments;

Get an array of all comments for a given node. Note that the nesting relative to other nodes is not preserved. If the node has no comments then this will return nil.

- (NSString *)nodeName;

Get the name of the node. If the name is not known this will return nil.

- (NSString *)innerText;

Get the text content of the node. If the node has no text content, this will return nil;

- (NSString *)innerXML;

Get the contents of the node as an XML-encoded string. This XML string will not include the container node itself.

- (NSString *)XMLString;

Get the node and its content as an XML-encoded string. If the node name is not known, the top level tag will be called <root>.

- (NSArray *)arrayValueForKeyPath:(NSString *)keyPath;

Works just like valueForKeyPath: except that the value returned will always be an array. So if there is only a single value, it will be returned as @[value].

- (NSString *)stringValueForKeyPath:(NSString *)keyPath;

Works just like valueForKeyPath: except that the value returned will always be a string. So if the value is a dictionary, the text value of innerText will be returned, and if the value is an array, the first item will be returned.

- (NSDictionary *)dictionaryValueForKeyPath:(NSString *)keyPath;

Works just like valueForKeyPath: except that the value returned will always be a dictionary. So if the collapseTextNodes option is enabled and the value is a string, this will convert it back to a dictionary before returning, and if the value is an array, the first item will be returned.

Usage

The simplest way to load an XML file is as follows:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"someFile" ofType:@"xml"];
NSDictionary *xmlDoc = [NSDictionary dictionaryWithXMLFile:filePath];

You can then iterate over the dictionary as you would with any other object tree, e.g. one loaded from a Plist.

To access nested nodes and attributes, you can use the valueForKeyPath syntax. For example to get the string value of <foo> from the following XML:

<root>
	<bar cliche="true">
		<foo>Hello World</foo>
	</bar>
	<banjo>Was his name-oh</banjo>
</root>

You would write:

NSString *foo = [xmlDoc valueForKeyPath:@"bar.foo"];

The above examples assumes that you are using the default setting for collapseTextNodes and alwaysUseArrays. If collapseTextNodes is disabled then you would instead access <foo>'s value by writing:

NSString *foo = [[xmlDoc valueForKeyPath:@"bar.foo"] innerText];

If the alwaysUseArrays option is enabled then would use one of the following, depending on the collapseTextNodes property:

NSString *foo = [[xmlDoc valueForKeyPath:@"bar.foo"] firstObject];
NSString *foo = [[[xmlDoc valueForKeyPath:@"bar.foo"] firstObject] innerText];

To get the cliche attribute of bar, you could write:

NSString *barCliche = [xmlDoc[@"bar] attributes][@"cliche"];

If the attributesMode is set to the default value of XMLDictionaryAttributesModePrefixed then you can also do this:

NSString *barCliche = [xmlDoc valueForKeyPath:@"bar._cliche"];

Or if it is set to XMLDictionaryAttributesModeUnprefixed you would simply do this:

NSString *barCliche = [xmlDoc valueForKeyPath:@"bar.cliche"];

Release Notes

Version 1.4.1

  • Upgraded for Xcode 8.2
  • Added tvOS and watchOS support to podspec

Version 1.4

  • Added dictionaryWithXMLParser: constructor method
  • Added wrapRootNode option as a nicer way to preserve root node name
  • No longer crashes if non-string values are used as keys or attributes
  • Now complies with the -Weverything warning level

Version 1.3

  • added stripEmptyNodes property (defaults to YES)
  • added arrayValueForKeyPath, stringValueForKeyPath and dictionaryValueForKeyPath methods to simplify working with data

Version 1.2.2

  • sharedInstance method no longer returns a new instance each time

Version 1.2.1

  • Removed isa reference, deprecated in iOS 7

Version 1.2

  • Exposed XMLDictionaryParser object, which can be used to configure the parser
  • Parsing options can now be changed without modifying the library
  • Added option to always encode properties as arrays
  • __name and __coment keys are no longer included by default
  • Apostrophe is now encoded as &apos;
  • removed attributeForKey: method

Version 1.1

  • Updated to use ARC
  • Added podspec

Version 1.0

  • Initial release

xmldictionary's People

Contributors

atomkirk avatar dzamataev avatar evermeer avatar gshaw avatar jfmiguel avatar nicklockwood 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  avatar

xmldictionary's Issues

Empty tags are parsed into an array?

If parse a tag like <ref></ref>,it's content is blank, it will be parsed into an array @[@""].I think, it need to be parsed into an empty string directly.

I do a few changes in the endText method.

- (void)endText
{
    if (TRIM_WHITE_SPACE)
    {
        self.text = (NSMutableString *)[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    }
    if (text && [XML_TEXT_KEY length])
    {
        id existing = [self.top objectForKey:XML_TEXT_KEY];
        if (existing)
        {
            if (![text isEqualToString:@""])
            {
                if ([existing isKindOfClass:[NSMutableArray class]])
                {
                    [(NSMutableArray *)existing addObject:text];
                }
                else
                {
                    [self.top setObject:[NSMutableArray arrayWithObjects:existing, text, nil] forKey:XML_TEXT_KEY];
                }
            }
        }
        else
        {
            [self.top setObject:text forKey:XML_TEXT_KEY];
        }
    }
    self.text = [NSMutableString stringWithString:@""];
}

Best regards.

innerXML results to unordered lists

I have this XML

<root>
    <bar cliche="true">
        <foo>
            <p>The <italic>quick</italic> brown fox jumps over the lazy dog</p>
        </foo>
    </bar>
    <banjo>Was his name-oh</banjo>
</root>

Whenever I use innerXML, it results to

<foo><p><italic>quick</italic>
The
brown fox jumps over the lazy dog</p></foo>

How to create null node by XMLString Method

1.I want to create a null node Like ,But when I call the method [body setValue:nil forKey:@"nullnode"],The dictionary no have this key and value,So I can't create this node by call the [body XMLString],How can I create the null node?

2.I wan‘t create CDATA node By "setvalue for key" method,But now I should call method like [header setValue:" forKey:@"user_id"]; ,But when I call the XMLString method ,the result string will like this : "<![CDATA[yezhichao]]> ",So Can we create a method to create the CDATA node?

Odd behaviour in processing certain nodes.

Hi Nick,

I have the following XML

<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<startXML>
    <Contact/>
    <Dashboards>
        <Name>Dagsomsætning ugedag</Name>
        <KPI>
            <KPIName>Total salg (tDKK)</KPIName>
            <CurrentValue>8281</CurrentValue>
            <TargetValue>592</TargetValue>
            <MaxTolerance>0</MaxTolerance>
            <MinTolerance>0</MinTolerance>
            <LowIsBetter>n</LowIsBetter>
            <LastUpdate>2015-04-18 19:20:23</LastUpdate>
            <Comment/>
            <URL/>
            <DataPoints>6846</DataPoints>
            <DataPoints>6255</DataPoints>
            <DataPoints>6268</DataPoints>
            <DataPoints>6662</DataPoints>
            <ShowElipses>y</ShowElipses>
        </KPI>
        <KPI>
            <KPIName>Total salg2 (tDKK)</KPIName>
            <CurrentValue>8281</CurrentValue>
            <TargetValue>592</TargetValue>
            <MaxTolerance>0</MaxTolerance>
            <MinTolerance>0</MinTolerance>
            <LowIsBetter>n</LowIsBetter>
            <LastUpdate>2015-03-18 09:20:23</LastUpdate>
            <Comment/>
            <URL/>
            <DataPoints>6846</DataPoints>
            <DataPoints>6255</DataPoints>
            <DataPoints>6268</DataPoints>
            <DataPoints>6662</DataPoints>
            <ShowElipses>y</ShowElipses>
        </KPI>
    </Dashboards>
    <Dashboards>
        <Name>Test Board</Name>
        <KPI>
            <KPIName>Test sales (tDKK)</KPIName>
            <CurrentValue>8281</CurrentValue>
            <TargetValue>592</TargetValue>
            <MaxTolerance>0</MaxTolerance>
            <MinTolerance>0</MinTolerance>
            <LowIsBetter>n</LowIsBetter>
            <LastUpdate>2015-03-18 09:20:23</LastUpdate>
            <Comment/>
            <URL/>
            <DataPoints>6846</DataPoints>
            <DataPoints>6255</DataPoints>
            <DataPoints>6268</DataPoints>
            <DataPoints>6662</DataPoints>
            <ShowElipses>y</ShowElipses>
        </KPI>
    </Dashboards>
</startXML>

I use the [NSDictionary valueForKeyPath] method. The first Dashboard seems to process ok with KPI being a dictionary of 9 key/pair values.

The last KPI does not however and just appears to be an array of 9 key/pair values.

Here is an image illustrating what I mean.

dfsxmlparser_m

Any ideas? Is it a bug or something I am not understanding? Why is it treating the 2nd dashboard KPI differently just because it is alone?

XMLString Not Correct

I have been using XMLDictionary with success, but ran into an issue. When I run:

NSString *xml = @"<Contacts><Contact><ixPerson>1</ixPerson><sName /><sAddress /><sCity /><sState /><sCity /><sState /></Contact><Contact><ixPerson>1</ixPerson><sName /><sAddress /><sCity /><sState /><sCity /><sState /></Contact><Contact><ixPerson>1</ixPerson><sName /><sAddress /><sCity /><sState /><sCity /><sState /></Contact><Contact><ixPerson>1</ixPerson><sName /><sAddress /><sCity /><sState /><sCity /><sState /></Contact></Contacts>";
XMLDictionaryParser *xmlParser = [[XMLDictionaryParser alloc] init];
xmlParser.stripEmptyNodes = false;
NSDictionary *xmlDictionary = [xmlParser dictionaryWithString:xml];
NSString *xmlTest = [xmlDictionary XMLString];
NSLog(@"dictionary: %@",xmlDictionary);
NSLog(@"xml: %@",xmlTest);

xmlTest has duplicates for sCity and sState. The logs have:

2014-09-06 02:03:24.430 Hineynu[2350:60b] dictionary: {
Contact = (
{
ixPerson = 1;
sAddress = {
};
sCity = (
{
},
{
}
);
sName = {
};
sState = (
{
},
{
}
);
},
{
ixPerson = 1;
sAddress = {
};
sCity = (
{
},
{
}
);
sName = {
};
sState = (
{
},
{
}
);
},
{
ixPerson = 1;
sAddress = {
};
sCity = (
{
},
{
}
);
sName = {
};
sState = (
{
},
{
}
);
},
{
ixPerson = 1;
sAddress = {
};
sCity = (
{
},
{
}
);
sName = {
};
sState = (
{
},
{
}
);
}
);
"__name" = Contacts;
}

2014-09-06 02:03:24.431 Hineynu[2350:60b] xml: <Contacts><Contact><ixPerson>1</ixPerson>
<sAddress/>
<sName/>
<sCity/>
<sCity/>
<sState/>
<sState/></Contact>
<Contact><ixPerson>1</ixPerson>
<sAddress/>
<sName/>
<sCity/>
<sCity/>
<sState/>
<sState/></Contact>
<Contact><ixPerson>1</ixPerson>
<sAddress/>
<sName/>
<sCity/>
<sCity/>
<sState/>
<sState/></Contact>
<Contact><ixPerson>1</ixPerson>
<sAddress/>
<sName/>
<sCity/>
<sCity/>
<sState/>
<sState/></Contact></Contacts>

Am I missing something? I am running XMLDictionary version 1.4

Export NSDictionary to XML File Format

This is a question, not an issue.

Your header on the project says that you can export any dictionary to XML, but I am confused to how I would go about doing this, unless i skipped over it, I don't see any method to do so in your code.

FYI: I love this framework, saved me hours of work and it works incredibly well.

Problem with @attributes

I haven't had a chance to dig into this yet, but when I try something like

[xmldoc valuForKeyPath:@"[email protected]"]

I get the following exception

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '[<__NSDictionaryM 0x8979d40> valueForKeyPath:]: this class does not implement the attributes operation.'

I've tried a few variations with no luck. Although

[xmldoc valueForKeyPath:@"link._rel"]

works, so this is not a show-stopper.

XMLString returning plist

XMLDictionary's [NSDictionary XMLString] method returns a plist XML on OS X 10.10.5 but returns a correct XML on OS X 10.7.5.

ordering of children is incorrect?

I've got an issue with the ordering of child nodes. Is ordering intended to be preserved or am I just doing something wrong?

Here's my xml:

<xpobjEdit id="" type="" backgroundColor="#CDCDCD" height="400px" width="100%">
        <editForm>
            <assetEdit id="" height="240px" width="100%"/>
            <textEdit name="name" attribute="name" label="Name" placeholder="Name" value="catdog"/>
            <longTextEdit name="description" attribute="description" label="Description" placeholder="Description" value="monkey elephant"/>
            <textEdit name="tags" attribute="tags" label="Tags" placeholder="(separate tags with commas)" value=""/>
            <locationCoordinateEdit name="location" label="Location" placeholder="" mapbutton="true" mapbuttonDisabled="true" value=""/>
        </editForm>
        <buttonBasic label="PREVIEW" color="#FFFFFF" backgroundColor="#CCCCCC" width="100%" align="center">
            <onClickCallback type="xperienceNavigate" xperience="$this" templateId="TBD" viewTransition="push:fromRight"/>
        </buttonBasic>
    </xpobjEdit>

and here's the result:

{
    "__name" = xpobjEdit;
    backgroundColor = "#CDCDCD";
    buttonBasic =     (
                {
            align = center;
            backgroundColor = "#CCCCCC";
            color = "#FFFFFF";
            label = PREVIEW;
            onClickCallback =             (
                                {
                    templateId = TBD;
                    type = xperienceNavigate;
                    viewTransition = "push:fromRight";
                    xperience = "$this";
                }
            );
            width = "100%";
        }
    );
    editForm =     (
                {
            assetEdit =             (
                                {
                    height = 240px;
                    id = "";
                    width = "100%";
                }
            );
            locationCoordinateEdit =             (
                                {
                    label = Location;
                    mapbutton = true;
                    mapbuttonDisabled = true;
                    name = location;
                    placeholder = "";
                    value = "";
                }
            );
            longTextEdit =             (
                                {
                    attribute = description;
                    label = Description;
                    name = description;
                    placeholder = Description;
                    value = "monkey elephant";
                }
            );
            textEdit =             (
                                {
                    attribute = name;
                    label = Name;
                    name = name;
                    placeholder = Name;
                    value = catdog;
                },
                                {
                    attribute = tags;
                    label = Tags;
                    name = tags;
                    placeholder = "(separate tags with commas)";
                    value = "";
                }
            );
        }
    );
    height = 400px;
    id = "";
    type = "";
    width = "100%";

In my case, the order of the children of editForm matter, but in the resulting dictionary doesn't preserve the order. I used the alwaysUseArrays flag as well. Maybe I have misunderstood it's purpose?

Thanks for the great work!

Removing key prefixes when using attributesMode=XMLDictionaryAttributesModeDiscard

When using XMLDictionaryAttributesModeDiscard I think the following XML should parse differently than it currently does.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <FindRoomsResponse xmlns="https://www.spa-booker.com/soap/business">
            <FindRoomsResult xmlns:a="https://www.spa-booker.com" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                <a:ArgumentErrors i:nil="true" />
                <a:ErrorCode>0</a:ErrorCode>
                <a:ErrorMessage i:nil="true" />
                <a:IsSuccess>true</a:IsSuccess>
                <a:Results xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
                    <b:anyType i:type="a:Room">
                        <a:Capacity>100</a:Capacity>
                        <a:Description i:nil="true" />
                        <a:ID>65571</a:ID>
                        <a:LocationID i:nil="true" />
                        <a:Name>My Room</a:Name>
                        <a:Treatments>
                            <b:int>752012</b:int>
                            <b:int>1483258</b:int>
                        </a:Treatments>
                        <a:DateCreated>2013-01-14T16:32:00</a:DateCreated>
                        <a:DateLastModified>2013-01-14T16:32:00</a:DateLastModified>
                    </b:anyType>
                </a:Results>
                <a:TotalResultsCount>1</a:TotalResultsCount>
            </FindRoomsResult>
        </FindRoomsResponse>
    </s:Body>
</s:Envelope>

currently with XMLDictionaryAttributesModeDiscard it outputs:

{
    "__name" = "s:Envelope";
    "s:Body" =     {
        FindRoomsResponse =         {
            FindRoomsResult =             {
                "a:ErrorCode" = 0;
                "a:IsSuccess" = true;
                "a:Results" =                 {
                    "b:anyType" =                     {
                        "a:Capacity" = 100;
                        "a:DateCreated" = "2013-01-14T16:32:00";
                        "a:DateLastModified" = "2013-01-14T16:32:00";
                        "a:ID" = 65571;
                        "a:Name" = "My Room";
                        "a:Treatments" =                         {
                            "b:int" =                             (
                                752012,
                                1483258
                            );
                        };
                    };
                };
                "a:TotalResultsCount" = 1;
            };
        };
    };
}

I think the prefixed xmlns namespace prefixes on each element should be stripped like this:

{
    Body =     {
        FindRoomsResponse =         {
            FindRoomsResult =             {
                ErrorCode = 0;
                IsSuccess = true;
                Results =                 {
                    anyType =                     {
                        Capacity = 100;
                        DateCreated = "2013-01-14T16:32:00";
                        DateLastModified = "2013-01-14T16:32:00";
                        ID = 65571;
                        Name = "My Room";
                        Treatments =                         {
                            int =                             (
                                752012,
                                1483258
                            );
                        };
                    };
                };
                TotalResultsCount = 1;
            };
        };
    };
    "__name" = Envelope;
}

I made a simple change to the library to do this:

- (void)parser:(__unused NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName attributes:(NSDictionary *)attributeDict
{
    [self endText];

    if (_attributesMode==XMLDictionaryAttributesModeDiscard) {
        NSUInteger loc = [elementName rangeOfString:@":"].location;
        if (loc != NSNotFound) {
            elementName = [elementName substringFromIndex:loc + 1];
        }
    }

    NSMutableDictionary *node = [NSMutableDictionary dictionary];
    switch (_nodeNameMode)

Not sure if this should go into the mainline branch or not... seems correct to me.

In XMLDictionary.m , in function - (NSDictionary *)attributes

when //it may happened when _[name] and [name] are both exist on XML creation, a name collision may be possible in function - (NSDictionary *)attributes . My use case is using this llbrary as the XML writer .

Found name collision in 64bit simulator, as the sequence [filteredDict allKeys] is indefinite

Fix had been applied as follow , please advice :

  • (NSDictionary *)attributes
    {
    NSDictionary *attributes = self[XMLDictionaryAttributesKey];
    if (attributes)
    {
    return [attributes count]? attributes: nil;
    }
    else
    {
    NSMutableDictionary *filteredDict = [NSMutableDictionary dictionaryWithDictionary:self];
    [filteredDict removeObjectsForKeys:@[XMLDictionaryCommentsKey, XMLDictionaryTextKey, XMLDictionaryNodeNameKey]];

    //it is mean to prevent the key collision issue for xml creation
    //I guess the performance impact on this should be minimal
    //start patch 
    for (NSString *key in  [filteredDict allKeys])
    {
    
        if (![key hasPrefix:XMLDictionaryAttributePrefix])
        {
             [filteredDict removeObjectForKey:key];
        }
    }
    //end patch
    for (NSString *key in [filteredDict allKeys])
    {
        [filteredDict removeObjectForKey:key];
        if ([key hasPrefix:XMLDictionaryAttributePrefix])
        {
           // currAttriValue= self[key];
            filteredDict[[key substringFromIndex:[XMLDictionaryAttributePrefix length]]] = self[key];
        }
    }
    return [filteredDict count]? filteredDict: nil;
    

    }
    return nil;
    }

Handle invalid xmlChar

Hi,
Is there anyway to handle invalid xmlChar. I know which character is broking my xml and i want to remove/replace it.

Option To Not Add Newlines Between Nodes

the XMLString method/property is adding \n between the nodes:

<Reminder><ixGroup>-1</ixGroup>\n<ixPerson>35270</ixPerson>\n<s>test\n\n6:30 PM Call\nTest</s>\n<dt>2014-09-25T01:30:00.000Z</dt>\n<ixService>165</ixService></Reminder>

Is there an option to not add \n?

NS1, NS2 and NS3

Hi,
I have a structure of soap like that:
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>env:Header/env:Headerenv:Body<env:Fault xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>env:Servercom.totvs.core.exception.ServiceFault<ns3:ServiceFault xmlns:ns2='http://service.ibanking.totvs.com' xmlns:ns3='http://service.ibanking.totvs.com/'>4S00011Acesso bloqueado. Entre em contato com sua agência./ns3:ServiceFault/env:Fault/env:Body/env:Envelope

Some node have a suffix like 'NS1', 'NS2' or 'NS3'.
Have a way to ignore it?
Example, in case:
ns3:ServiceFault

ignore the 'ns3:' and use only 'ServiceFault' in valueForKeyPath?

How to grab XML file on Desktop

Is this how to correctly grab the XML file because it doesn't seem to letting me grab the XML file so I can parse the data?

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"/Users/mycomputer/Desktop/foo" ofType:@"xml"];
NSDictionary *xmlDoc = [NSDictionary dictionaryWithXMLFile:filePath];

if(xmlDoc){
    NSLog(@"Grabbed the doc");
}else{
    NSLog(@"failed to grab the doc");
}

NSString *frame = [xmlDoc valueForKey:@"Frame"];

NSLog(@"Output: %@", frame);

Attribute parsing for XML response

Hi,

Is there attribute parsing support for XML response? I looked at all the methods and properties, but did not get any such methods. Also, I gone through the sample example, but it does not contain such scenarios as below:

       <SrcGeos>
            <Geo>
                <Level1 DisplayText="Sao Paulo" Code="saopaulo"/>
                <Level2 DisplayText="Sao Paulo" Code="saopaulo"/>
                <City DisplayText="Sao Paulo" Code="saopaulo"/>
                <Country DisplayText="Brazil" Code="brazil"/>
                <Latitude>-23.5475</Latitude>
                <Longitude>-46.63611</Longitude>
                <Region DisplayText="Latin America" Code="latinamerica"/>
            </Geo>
        </SrcGeos>

XMLString returns wrong result

dictionary {
 root: array {
  .... 100 items
 }
}

returns 12...

in XMLStringForNode if node is an array, subcalls of XMLStringForNode on each array element should be called with nodeName:nil.

if ([node isKindOfClass:[NSArray class]])
{
    NSMutableArray *nodes = [NSMutableArray arrayWithCapacity:[node count]];
    for (id individualNode in node)
    {
        [nodes addObject:[self XMLStringForNode:individualNode withNodeName:nil]];
    }
    return [nodes componentsJoinedByString:@"\n"];
}
...

and if nodeName is nil. result has to be without nodeName around.

if(nodeName)
{
    return [NSString stringWithFormat:@"<%1$@%2$@>%3$@</%1$@>", nodeName, attributeString, innerXML];
}
else
{
    return [NSString stringWithFormat:@"%@", innerXML];
}
...

Parser wrong from nsstring

I added your lib to my source code. When I parser from the returned data from Server, everything is ok except one thing: There is a special Node, it returned an array type but original data from my server is string type.

This special node has format "< / NODENAME>". When parse this node, the dictionary return the array type for this node.

Can you please help me to fix this bug? Thanks so much.

support duplicated tags?

i have a xml file like that:

<?xml version="1.0"  encoding="UTF-8"?>
<root xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
    <person id="1" value="a">
        <firstName>zhang</firstName>
        <lastName>sansan</lastName>string after element lastname
        <age>21
            <china>23</china>
            <zhou>21</zhou>
        </age>
    </person>
    <person id="2" value="b">
        <firstName>li</firstName>
        <lastName>sisisi</lastName>
        <age>31</age>
    </person>string after element person
    <man  value="b">
        <firstName>li</firstName>
        <lastName>sisisi</lastName>
        <age>21
            <china>23</china>
            <zhou>21</zhou>
        </age>
    </man>
    <woman type="white"/>
</root>

when i use like below:
NSDictionary *personXml=[NSDictionary dictionaryWithXMLFile:xmlFilePath];
NSLog(@"personXml: %@", personXml);
NSLog(@"path value[%@]",[personXml stringValueForKeyPath:@"person.age.china"]);

it generate a NSUnknownKeyException:
2014-10-26 14:39:07.098 XMLTest[1215:70b] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0xeb1f660> valueForUndefinedKey:]: this class is not key value coding-compliant for the key china.

i think it should be a duplicated tags problem, is it right?

parse failed

let dict = XMLDictionaryParser.sharedInstance().dictionaryWithString(" 11002601 ab735a258a90e8e1-6bee54fcbd896b2a-367f697f88b3265598595c016b32cea1 550<title></title> 142301860351k ")
println(dict)

if I remove the contents between blue arrows, it will work great.
a

Shared Instance always returns a new instance

Since the sharedInstance method always returns a new instance, changing settings of the shared instance (such as collapseTextNodes) has no effect.

+ (XMLDictionaryParser *)sharedInstance
{
    return [[self alloc] init];
}

should be

+ (XMLDictionaryParser *)sharedInstance
{
    static dispatch_once_t once;
    static XMLDictionaryParser *sharedInstance;
    dispatch_once(&once, ^ { sharedInstance = [[XMLDictionaryParser alloc] init]; });
    return sharedInstance;
}

If XML Data has XML declarations, boom!

I have a XML data below. I cannot parse that because it has some XML declarations. Am I doing something wrong? Or do I have to delete declarations manually?

<?xml version="1.0" encoding="utf-8"?>
<OBJECT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/">
  <NAME>name</NAME>
  <CODE>nm</CODE>
  <ID>10001</ID>
</OBJECT>

tvos support

Do you think to update your pod to support this new platform soon? Or a branch to avoid breaking the master until CocoaPods release a version working with tvos?

I don't think you will have any issue to handle it with the current version.

foundCDATA not fired

code example with url: http://matas-dev-stag.agillic.eu/apps/rest/userservice/loginuser?msisdn=20204545&password=12345678

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//TODO use cache regardless of header
manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

AFHTTPRequestOperation *operation = [manager GET:strUrl parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSDictionary *response =[NSDictionary dictionaryWithXMLParser:responseObject];
    completion(response);
}                                        failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    completion(nil);    
}];

return operation;

}

Issue in parsing an array from XML

Hi,

I am facing an issue while parsing an array with single element in XML. Please refer below example for more details.

<Xml>
    <Item>
        <created_at>Sat Apr 14 00:20:07 +0000 2012</created_at>
        <text>Sample text</text>
        <id_str>190957570511478784</id_str>
    </Item>
    <Item>
        <created_at>Sat Apr 14 00:20:07 +0000 2012</created_at>
        <text>Sample text</text>
       <id_str>190957570511478784</id_str>
    </Item>
</Xml>

If I am going to parse above xml in to dictionary I will get "Item" as an Array. But if there is only single element of "Item" it will be consider as a dictionary. It happen many times when there is a case of getting a single element in array and other time it has multiple elements, e.g location kind of APIs.

How can I manage this case with my objective-c property type? In above case if I take "Item" as NSArray type and in response if I get only single element of "Item" it will be converted to NSDictionary type, and I will get a crash in this case.

Please help me in above scenario and guide me if my understating is not proper.

parser less

I have xml string like this,in the group node ,the key cann't be parsed,because it contain '&'.
how can i solve it?
<key>Qo5n0tSUYBUFBJ1ttCk3ffMXa6E51__iFrBIeQ..&q=bj0xJmE8mJgYmC</key>

Parents with One Child break parsing pattern. They SHOULD be put in an Array also

If a parent has children, the children are instances of NSDictionary and put into an array

Parent
-
- Child0
- @"Attrib0"
- obj
- @"Attrib1"
- obj
- Child1
- @"Attrib0"
- obj
- @"Attrib1"
- obj
- Child2
- @"Attrib0"
- obj
- @"Attrib1"
- obj

If a parent has one child, an instance of NSDictionary is created, but not put into an array.

Parent
- Child0
- @"Attrib0"
- obj
- @"Attrib1"
- obj

Is this by design?

What should happen, for bother cases, that the children instances be put into an array, even if there is only one child.

Parent
-
- Child0
- @"Attrib0"
- obj
- @"Attrib1"
- obj

problem with empty elements

when i have a empty element it doesnt add id as null or empty to dictionary < example / >

example

NSString *xmlString = @"< ?xml version="1.0" encoding="UTF-8"? > < note > < to > Tove < /to > < example /> < body > Don't forget me this weekend! < /body > < /note >";
NSDictionary *resultD = [[XMLDictionaryParser sharedInstance] dictionaryWithString:xmlString];
dictionary shold have a @"example" key with empty string

Fail to parse CData

My xml contains data as below.

When it tries to parse that data it great the queue return the data till that part.

XMLDictionary Crashing when being used within NSURLSessionDataTask Completion block

I'm trying to use XMLDictionary to parse some RSS feeds within the NSURLSessionDataTask completion block. When using XMLData about 1/2 the RSS feeds crash XMLDictionary with "BAD_ACCESS". I tried to solve this by converting the NSData to NSString and using XMLString. This solved the "BAD_ACCESS" issue but now I'm getting "[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array" Specifically with this RSS Feed: http://feeds.ign.com/ignfeeds/podcasts/wii/

Now, if I parse the RSS feed OUTSIDE of the completion block, it works fine no problem. But when I try and parse it within the Completion block, I get s crashes.

Any idea how to solve this?

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.