0

I have an xml like this:

    <root>
   ...
    <images xmlns:a="http://.../Arrays">
        <a:string>http://images...233/Detail.jpg</a:string>
        <a:string>http://images....233/Detail2.jpg</a:string>
    </images>
   ...
   <images xmlns:a="http://.../Arrays">
        <a:string>http://images...233/Detail3.jpg</a:string>
        <a:string>http://images....233/Detail4.jpg</a:string>
        <a:string>http://images....233/Detail5.jpg</a:string>
    </images>
....
<images xmlns:a="http://.../Arrays">
        <a:string>http://images...233/Detail6.jpg</a:string>
        <a:string>http://images....233/Detail7.jpg</a:string>
    </images>
   ....
<root>

How can i iterate to put all my images in NSArray ?

samir
  • 4,501
  • 6
  • 49
  • 76

2 Answers2

0

How can i iterate to put all my images in NSArray ?

I don't know what you mean by NSArray.

Usually an XPath engine exposes a method like SelectNodes(string XpathExpression), possibly with overloads for a NamespaceManager object - argument.

And this method typically returns an XmlNodelist object, which contains all results and allows to iterate over them.

One XPath expression that selects all the text nodes that contain images in the provided XML document:

<images xmlns:a="http://.../Arrays">
    <a:string>http://images...233/Detail.jpg</a:string>
    <a:string>http://images....233/Detail2.jpg</a:string>
</images>

is:

/*/*/text()

This selects any text node whose parent is a child of the top element in the XML document -- in this case such nodes are exactly the two text nodes with string value, respectively:

"http://images...233/Detail.jpg"

and

"http://images....233/Detail2.jpg" .

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • `NSArray` is the standard array/list class in Apple's Cocoa and Cocoa Touch frameworks. – jscs Feb 22 '12 at 18:26
0

To do this on an iOS device, you would preferably use a third-party C library that implements XPath evaluation for you, as the built-in XML support provided for iOS does not. Your best bet is using libxslt, but because the downloadable version of libxslt come in the form of a dynamic library it can't be used directly on iOS. Instead, you'll want to pull down the source code for libxslt and build it directly into your app. See this SO post for more information on getting libxslt to work on iOS.

Once you have libxslt working in your project, you can use C code to parse the XML and evaluate arbitrary XPath expressions such as "///text()", as was suggested by @Dmitre Novatchev. There are many variants on how you can do this, but something like this gives you an example:

CFArrayRef findImages(CFStringRef filename) {

    xmlInitParser();
    LIBXML_TEST_VERSION

    // Parse XML template document into DOM tree
    CFIndex filenameLength = CFStringGetLength(filePath);
    char *fileNameCString = (char *) calloc(filenameLength + 1, sizeof(char));
    CFStringGetCString(filePath, fileNameCString, filenameLength + 1, kCFStringEncodingUTF8);

    xmlDocPtr doc = xmlReadFile(fileNameCString, NULL, 0);
    if (doc == NULL) 
    {
        // Error - File not readable
        free(fileNameCString);
        return nil;
    }
    else
    {
        free(fileNameCString);
        xmlCleanupParser();
    }

    /* Create xpath evaluation context */
    xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
    if(xpathCtx == NULL) 
    {
        // Error - Failed to create Xpath context
        return NULL;
    }


    /* Evaluate xpath expression */
    char *xpathCString = "/*/*/text()";
    xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(BAD_CAST xpathCString, xpathCtx);
    if(xpathObj == NULL) 
    {
        // Error - Failed to evaluate XPath
        xmlXPathFreeContext(xpathCtx); 
        return NULL;
    }
    xmlNodeSetPtr resultNodes = xpathObj->nodesetval;


    // You'll want to double-check the following part: I don't have sample code for
    // this so I can't be certain this is 100% correct, but it gets the idea across!

    CFMutableArrayRef result = CFArrayCreate(kCFAllocatorDefault, 0, NULL);
    for (int i = 0; i < resultNodes->nodeNr; i++) {
        char *imageCString = xmlNodeGetContent(resultNodes->nodeTab[i]);
        CFStringRef imageString = CFStringCreateWithCString(kCFAllocatorDefault, imageCString, kCFStringEncodingUTF8);
        CFArrayAppendValue(result, imageString);
    }

    return result;
}

I've put this code sample together based on some working sample code I had for evaluating an XPath expression, but the end part where I assemble it into an array is off the top of my head: It might not work completely right!

Note that this function takes a CFString for the filename of the XML file and returns a CFArray for the result. These types are "toll-free bridged" with the Objective-C NSString and NSArray types. That means you can call them from objective-C with the "normal" types you are used to using, and they will be correctly understood in the C code I've provided.

Community
  • 1
  • 1
Tim Dean
  • 8,253
  • 2
  • 32
  • 59
  • Thanks for your answer. i am using GDataXML to parse my XML and it's working fine, but i have a trouble to iterate with this portion of my xml ? – samir Feb 22 '12 at 19:59
  • If you have already worked with GDataXML, can you show me how you will put all the .png in NSMutableArray for example ? thanks again – samir Feb 22 '12 at 20:00
  • I've never worked with GDataXML - But a quick google search turned up http://www.raywenderlich.com/725/how-to-read-and-write-xml-documents-with-gdataxml, where they provide an example of evaluating an XPath expression against the document and returning the results as an NSArray – Tim Dean Feb 22 '12 at 20:04