Added xpath support

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@14352 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2002-08-27 15:46:15 +00:00
parent 7e2248c901
commit 505cf97c4f
4 changed files with 263 additions and 4 deletions

View file

@ -1,3 +1,9 @@
2002-08-27 Richard Frith-Macdonald <rfm@gnu.org>
* Source/Additions/GSXML.m: Integrated GSXPath code by Nicola Pero
provides an API to use the xpath support built into libxml from
version 2.3 onwards.
2002-08-27 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSData.m: ([-writeToFile:atomically:]) Removed bogus line

View file

@ -9,6 +9,7 @@
Integrated by Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: September 2000
GSXPath by Nicola Pero <nicola@brainstorm.co.uk>
This file is part of the GNUstep Base Library.
@ -269,6 +270,74 @@
@interface GSHTMLSAXHandler : GSSAXHandler
@end
@class GSXPathObject;
/**
* Using this library class is trivial. Get your GSXMLDocument. Create
* a GSXPathContext for it.
*
* GSXPathContext *p = [[GSXPathContext alloc] initWithDocument: document];
*
* Then, you can use it to evaluate XPath expressions:
*
* GSXPathString *result = [p evaluateExpression: @"string(/body/text())"];
* NSLog (@"Got %@", [result stringValue]);
*
*/
@interface GSXPathContext : NSObject
{
void *_lib; // xmlXPathContext
GSXMLDocument *_document;
}
- (id) initWithDocument: (GSXMLDocument*)d;
- (GSXPathObject*) evaluateExpression: (NSString*)XPathExpression;
@end
/** XPath queries return a GSXPathObject. GSXPathObject in itself is
* an abstract class; there are four types of completely different
* GSXPathObject types, listed below. I'm afraid you need to check
* the returned type of each GSXPath query to make sure it's what you
* meant it to be.
*/
@interface GSXPathObject : NSObject
{
void *_lib; // xmlXPathObject
GSXPathContext *_context;
}
@end
/**
* For XPath queries returning true/false.
*/
@interface GSXPathBoolean : GSXPathObject
- (BOOL) booleanValue;
@end
/**
* For XPath queries returning a number.
*/
@interface GSXPathNumber : GSXPathObject
- (double) doubleValue;
@end
/**
* For XPath queries returning a string.
*/
@interface GSXPathString : GSXPathObject
- (NSString *) stringValue;
@end
/**
* For XPath queries returning a node set.
*/
@interface GSXPathNodeSet : GSXPathObject
- (unsigned int) length;
/** Please note that index starts from 0. */
- (GSXMLNode *) nodeAtIndex: (unsigned)index;
@end
#endif /* STRICT_MACOS_X */
#endif /* STRICT_OPENSTEP */

View file

@ -62,6 +62,7 @@
#include <libxml/SAX.h>
#include <libxml/HTMLparser.h>
#include <libxml/xmlmemory.h>
#include <libxml/xpath.h>
extern int xmlDoValidityCheckingDefaultValue;
extern int xmlGetWarningsDefaultValue;
@ -2826,6 +2827,187 @@ fatalErrorFunction(void *ctx, const char *msg, ...)
}
@end
@implementation GSXPathObject
- (id) init
{
RELEASE(self);
return nil;
}
/* Internal method. */
- (id) _initWithNativePointer: (xmlXPathObject *)lib
context: (GSXPathContext *)context
{
_lib = lib;
/* We RETAIN our context because we might be holding references to nodes
* which belong to the document, and we must make sure the document is
* not freed before we are. */
ASSIGN (_context, context);
return self;
}
/* This method is called by GSXPathContext when creating a
* GSXPathObject to wrap the results of a query. It assumes that lib
* is a pointer created by xmlXPathEval (), and that we are now taking
* on responsibility for freeing it. It then examines lib, and
* replaces itself with an object of the appropriate subclass. */
+ (id) _newWithNativePointer: (xmlXPathObject *)lib
context: (GSXPathContext *)context
{
switch (lib->type)
{
case XPATH_NODESET:
return [[GSXPathNodeSet alloc] _initWithNativePointer: lib
context: context];
break;
case XPATH_BOOLEAN:
return [[GSXPathBoolean alloc] _initWithNativePointer: lib
context: context];
break;
case XPATH_NUMBER:
return [[GSXPathNumber alloc] _initWithNativePointer: lib
context: context];
break;
case XPATH_STRING:
return [[GSXPathString alloc] _initWithNativePointer: lib
context: context];
break;
default:
/* This includes:
case XPATH_UNDEFINED:
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
case XPATH_USERS:
case XPATH_XSLT_TREE:
*/
return [[self alloc] _initWithNativePointer: lib context: context];
}
}
- (void) dealloc
{
xmlXPathFreeObject (_lib);
RELEASE (_context);
[super dealloc];
}
@end
@implementation GSXPathBoolean
- (BOOL) booleanValue
{
return ((xmlXPathObject*)_lib)->boolval;
}
- (NSString *) description
{
return ([self booleanValue] ? @"true" : @"false");
}
@end
@implementation GSXPathNumber
- (double) doubleValue
{
return ((xmlXPathObject*)_lib)->floatval;
}
- (NSString *) description
{
return [NSString stringWithFormat: @"%f", [self doubleValue]];
}
@end
@implementation GSXPathString
- (NSString *) stringValue
{
xmlChar *string = ((xmlXPathObject*)_lib)->stringval;
return [NSString stringWithUTF8String: string];
}
- (NSString *) description
{
return [NSString stringWithFormat: @"%@", [self stringValue]];
}
@end
@implementation GSXPathNodeSet
- (unsigned int) length
{
if (xmlXPathNodeSetIsEmpty (((xmlXPathObject*)_lib)->nodesetval))
{
return 0;
}
return xmlXPathNodeSetGetLength (((xmlXPathObject*)_lib)->nodesetval);
}
- (GSXMLNode *) nodeAtIndex: (unsigned)index
{
if (xmlXPathNodeSetIsEmpty (((xmlXPathObject*)_lib)->nodesetval))
{
return nil;
}
else
{
xmlNode *node;
GSXMLNode *n;
node = xmlXPathNodeSetItem (((xmlXPathObject*)_lib)->nodesetval, index);
n = [GSXMLNode alloc];
return [n _initFrom: node parent: self];
}
}
- (NSString *) description
{
return [NSString stringWithFormat: @"NodeSet (length %d)", [self length]];
}
@end
@implementation GSXPathContext
- (id) initWithDocument: (GSXMLDocument *)d
{
ASSIGN (_document, d);
((xmlXPathContext*)_lib) = xmlXPathNewContext ([_document lib]);
((xmlXPathContext*)_lib)->node = xmlDocGetRootElement ([_document lib]);
return self;
}
- (GSXPathObject *) evaluateExpression: (NSString *)XPathExpression
{
xmlXPathCompExpr *comp;
xmlXPathObject *res;
GSXPathObject *result;
comp = xmlXPathCompile ([XPathExpression UTF8String]);
if (comp == NULL)
{
/* Maybe an exception would be better ? */
return nil;
}
res = xmlXPathCompiledEval (comp, ((xmlXPathContext*)_lib));
result = [GSXPathObject _newWithNativePointer: res context: self];
AUTORELEASE (result);
xmlXPathFreeCompExpr (comp);
return result;
}
- (void) dealloc
{
xmlXPathFreeContext (_lib);
RELEASE (_document);
[super dealloc];
}
@end
/*
* need this to make the linker happy on Windows
*/

View file

@ -234,10 +234,12 @@ static Class NSURLHandleClass = 0;
*/
- (void) addClient: (id <NSURLHandleClient>)client
{
RETAIN((id)client);
[_clients removeObjectIdenticalTo: client];
[_clients addObject: client];
RELEASE((id)client);
id o = client;
RETAIN(o);
[_clients removeObjectIdenticalTo: o];
[_clients addObject: o];
RELEASE(o);
}
/**