63 #import <libxml/tree.h>
64 #import <libxml/xmlwriter.h>
66 #define OONodeArray OOArray<OONode>
67 #define OONodes OONodeArray
69 static NSString *kOOChildren =
@".children", *kOONodeText =
@".nodeText", *kOOTagName =
@"@tagName", *kOOTagPrefix =
@"@tagPrefix";
109 NSMutableDictionary *ref2;
117 [
alloc() setObject:(id)kCFNull forKey:kOOTagName];
129 [
alloc() setObject:tagName forKey:kOOTagName];
132 [
alloc() setObject:tagName forKey:kOOTagName];
134 [
get() setObject:nodeText forKey:kOONodeText];
136 NSMutableArray *
children = node[kOOChildren].alloc( [NSMutableArray
class] );
137 [children addObject:nodeText];
164 NSMutableArray *
children = node[kOOChildren].alloc( [NSMutableArray
class] );
165 [children addObject:val.get()];
166 NSString *tagName = [val objectForKey:kOOTagName];
167 if ( tagName && tagName != (
id)kCFNull ) {
168 NSMutableArray *siblings = node[tagName].alloc( [NSMutableArray
class] );
169 [siblings addObject:val.get()];
180 return [
get() objectForKey:kOOChildren];
186 return [
get() objectForKey:kOONodeText];
196 class OONodeArraySub :
public OOArraySub<OOString> {
197 friend class OONodeSub;
199 OONodeArraySub( OODictionarySub<NSMutableArray *> *ref,
int sub ) : OOArraySub<
OOString>( ref, sub ) { }
201 OOArraySub<NSMutableDictionary *> *nodeReference( BOOL refer = YES )
const {
202 if ( refer && this->
dref->aref->references )
203 this->
dref->aref->references++;
204 return this->
dref->aref;
209 OOArraySub<OOString>::set( val );
210 if ( ![kOOChildren isEqualToString:
dref->key] ) {
212 (NSMutableDictionary *)
root->
get() :
dref->parent( YES );
213 OONodeArray children = node[kOOChildren].alloc( [NSMutableArray
class] );
214 children +=
OONode( val );
215 if ( ![val objectForKey:kOOTagName] )
216 [val setObject:
dref->key forKey:kOOTagName];
223 return nodeReference( NO )->get();
230 return node().text();
236 oo_inline OONodeSub operator [] (
id sub )
const;
238 oo_inline OONodeSub operator [] (
const char *sub )
const;
247 class OONodeSub :
public OODictionarySub<OOString> {
248 friend class OONodeArraySub;
251 void supportXPath() {
254 unichar char0 = Key[0];
255 if ( char0 !=
'@' && char0 !=
'.' ) {
258 NSInteger pmax = [path
count]-1, firstCharOfLast = [*path[-1] length] ? (*path[-1])[0] : 0;
260 if ( firstCharOfLast !=
'@' && firstCharOfLast !=
'.' ) {
266 OODictionarySub<NSMutableArray *> *exp =
root ?
267 new OODictionarySub<NSMutableArray *>(
root, *path[0] ) :
268 new OODictionarySub<NSMutableArray *>( aref, *path[0] );
271 for (
int i=1 ; i<=pmax ; i++ ) {
274 if ( [p length] && iswdigit( p[0] ) ) {
279 aref = (OOArraySub<NSMutableDictionary *> *)
new OONodeArraySub( exp, idx );
280 aref->references = 1;
284 if ( (p = path[i]) ==
@"*" )
286 exp =
new OODictionarySub<NSMutableArray *>(
aref, p );
300 oo_inline OONodeSub( OOArraySub<NSMutableDictionary *> *
ref,
id sub ) : OODictionarySub<
OOString>( ref, sub ) {
303 oo_inline OONodeSub( OODictionarySub<NSMutableDictionary *> *
ref,
id sub ) : OODictionarySub<
OOString>( ref, sub ) {
308 OODictionarySub<OOString>::set( val );
309 if ( [kOONodeText isEqualToString:this->key] ) {
311 NSMutableArray *children = textNode[kOOChildren].alloc( [NSMutableArray
class] );
312 [children addObject:val];
323 oo_inline OONodeSub &
operator = (
const OOArraySub<OOString> &val ) {
set( val.get() );
return *
this; }
324 oo_inline OONodeSub &
operator = (
const OODictionarySub<OOString> &val ) {
set( val.get() );
return *
this; }
334 this->
aref->set( val.get() );
return *
this;
341 if ( this->
aref->references )
342 this->
aref->references++;
343 return OONodeSub( this->aref, sub );
346 return (*
this)[(id)sub];
353 if ( this->
aref->dref->references )
354 this->
aref->dref->references++;
355 OONodeArraySub *node =
new OONodeArraySub( this->
aref->dref, sub );
356 node->references = 1;
357 OONodeSub *children =
new OONodeSub( (OOArraySub<NSMutableDictionary *> *)node, kOOChildren );
358 children->references = 1;
359 return OONodeArraySub( (OODictionarySub<NSMutableArray*> *)children, 0 );
366 return this->
aref ? this->
aref->parent( NO ) : nil;
373 return nodes()[(int)(which == NSNotFound ?
aref->idx : which)];
380 return this->
get( NO );
387 return [nodes() count];
397 return [this->
parent( NO ) objectForKey:kOOChildren];
406 for ( NSMutableDictionary *n in *in ) {
409 for( NSString *key in [*node allKeys] ) {
410 unichar c0 = [key characterAtIndex:0];
411 if ( c0 ==
'.' || c0 ==
'@' )
413 values[key] = node[key];
420 return dictionaries();
425 OODictionarySub<OONode> *step1 =
new OODictionarySub<OONode>( (
OODictionary<OONode> *)
this, kOOChildren );
426 step1->references = 1;
427 return (*step1)[sub];
431 return OONodeSub(
this, sub );
435 return (*
this)[(id)sub];
442 inline OONodeSub OONodeArraySub::operator [] (
id sub )
const {
443 return OONodeSub( nodeReference(), sub );
446 inline OONodeSub OONodeArraySub::operator [] (
cOOString sub )
const {
447 return (*
this)[(id)sub];
450 inline OONodeSub OONodeArraySub::operator [] (
const char *sub )
const {
454 template <
typename ETYPE>
456 template <
typename ETYPE>
480 inline BOOL
operator != (
const OONodeArraySub &left,
const OONode &val ) {
return !(left == val); }
508 OOString tagString = value, unique = tagCache[tagString];
510 unique = tagCache[tagString] = tagString;
516 const char *colon = strchr( name,
':' );
521 char *out = buff+10, *optr = out;
523 *optr++ = tolower( *name++ );
531 OONode parent = stack[-1];
533 children = parent[kOOChildren].alloc( [NSMutableArray
class] );
536 static OOPattern nonWhiteSpace(
@"\\S" );
539 regmatch_t match[] = {{0, len}};
543 if ( children>0 && [*children[-1] isKindOfClass:[NSMutableString
class]] )
544 *textChildren[-1] += node;
550 textChildren += text;
551 if ( ![*parent objectForKey:kOONodeText] )
552 [*parent setObject:node forKey:kOONodeText];
563 root[
@"/"] = index =
OONode();
565 context = xmlCreatePushParserCtxt( &handlers,
this, NULL, 0, NULL);
569 const char *bytes = (
const char *)[chunk bytes];
570 int length = (int)[chunk length];
571 while ( length > 0 && bytes[length-1] ==
'\000' )
573 return xmlParseChunk(context, bytes, length, 0);
580 xmlParseChunk(context, NULL, 0, 1);
581 xmlFreeParserCtxt(context);
587 static void objcppStartElement(
void *ctx,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI,
588 int nb_namespaces,
const xmlChar **namespaces,
589 int nb_attributes,
int nb_defaulted,
const xmlChar **attributes) {
597 [element setObject:sax.
unique( (
const char *)prefix ) forKey:kOOTagPrefix];
599 for (
int ns=0 ; ns < nb_namespaces ; ns++ ) {
600 struct _ns {
const char *prefix, *nsURI; } *nptr =
601 (
struct _ns *)(namespaces + ns*
sizeof *nptr/
sizeof nptr->prefix);
603 snprintf( name,
sizeof name-1, nptr->prefix ?
"@xmlns:%s" :
"@xmlns%.0s", nptr->prefix );
604 [element setObject:sax.
unique( nptr->nsURI ) forKey:sax.
unique( name )];
608 for (
int attr_no=0 ; attr_no < nb_attributes ; attr_no++ ) {
609 struct _attrs {
const char *localName, *prefix, *uri, *value, *end; } *aptr =
610 (
struct _attrs *)(attributes + attr_no*
sizeof *aptr/
sizeof aptr->localName);
611 NSInteger vlen = aptr->end-aptr->value;
613 OOString value( aptr->value, vlen ), trouble =
@"&";
615 if ( !!value[trouble] )
616 value[trouble] =
@"&";
618 snprintf( name,
sizeof name-1,
"@%s", sax.
normalize( aptr->localName, name ) );
619 [element setObject:sax.
unique( value ) forKey:sax.
unique( name )];
622 sax.
stack += element;
626 static void objcppEndElement(
void *ctx,
const xmlChar *localname,
const xmlChar *prefix,
const xmlChar *URI) {
632 for ( NSDictionary *n in *sax.
stack ) {
634 node[
@"/"] += element;
637 sax.
index += element;
641 static void objcppCharacters(
void *ctx,
const xmlChar *ch,
int len) {
643 sax.
addNode(
OOString( (
const char *)ch, len ).
get(), (
const char *)ch, len );
646 static void objcppCData(
void *ctx,
const xmlChar *value,
int len) {
648 NSData *data = [[NSData alloc] initWithBytes:value length:len];
653 static void objcppSAXError(
void *ctx,
const char *msg, ...) {
654 va_list argp; va_start(argp, msg);
655 NSLogv(
"OOXMLSaxParser Error - "+
OOString( msg ), argp );
662 memset( &handlers, 0,
sizeof handlers );
663 handlers.startElementNs = objcppStartElement;
664 handlers.endElementNs = objcppEndElement;
665 handlers.characters = objcppCharacters;
666 handlers.initialized = XML_SAX2_MAGIC;
667 handlers.error = objcppSAXError;
690 char name[1000], value[10000];
694 OOWarn(
@"Error code returned from %s(): %d", what, rc );
698 checkrc(
"xmlTextWriterWriteFormatString", xmlTextWriterWriteFormatString( writer,
"\n%*s", level*2,
"" ) );
702 NSString *tagName = [*node objectForKey:kOOTagName];
704 if ( tagName && tagName != (
id)kCFNull ) {
709 NSString *tagPrefix = [*node objectForKey:kOOTagPrefix];
711 [tagPrefix getCString:name maxLength:
sizeof name-1 encoding:NSUTF8StringEncoding];
717 [tagName getCString:name+strlen(name) maxLength:
sizeof name-1-strlen(name) encoding:NSUTF8StringEncoding];
718 checkrc(
"xmlTextWriterStartElement", xmlTextWriterStartElement( writer, (xmlChar *)name ) );
720 for ( NSString *attr in [*node allKeys] ) {
721 if ( attr == kOOTagName || attr == kOOTagPrefix || [attr length] == 0 || [attr characterAtIndex:0] !=
'@' )
723 [attr getCString:name maxLength:
sizeof name-1 encoding:NSUTF8StringEncoding];
724 [[*node objectForKey:attr] getCString:value maxLength:
sizeof value-1 encoding:NSUTF8StringEncoding];
725 checkrc(
"xmlTextWriterWriteAttribute", xmlTextWriterWriteAttribute( writer, (xmlChar *)name+1, (xmlChar *)value ) );
729 BOOL hadChildElements = NO;
731 for (
id child in *children )
732 if ( [child isKindOfClass:[NSString
class]] )
733 checkrc(
"xmlTextWriterWriteString", xmlTextWriterWriteString( writer, (xmlChar *)[child UTF8String] ) );
734 else if ( [child isKindOfClass:[NSData
class]] )
735 checkrc(
"xmlTextWriterWriteFormatCDATA", xmlTextWriterWriteFormatCDATA( writer,
"%.*s", (
int)[child length], (
char *)[child bytes] ) );
738 hadChildElements = YES;
741 if ( tagName != (
id)kCFNull ) {
745 checkrc(
"xmlTextWriterEndElement", xmlTextWriterEndElement( writer ) );
756 xmlBufferPtr buf = xmlBufferCreate();
757 writer = xmlNewTextWriterMemory(buf, 0);
759 NSString *encoding = *node[
@"@encoding"];
760 checkrc(
"xmlTextWriterStartDocument", xmlTextWriterStartDocument(writer, NULL, encoding ? [encoding UTF8String] :
"UTF-8", NULL) );
764 xmlTextWriterEndDocument(writer);
765 xmlFreeTextWriter(writer);
767 OOData data = [[NSData alloc] initWithBytes:buf->content length:strlen((
const char *)buf->content)];
791 this->action = action;
795 root[prefix+
@":Envelope/@"+prefix+
@":encodingStyle"] =
@"http://schemas.xmlsoap.org/soap/encoding/";
796 root[prefix+
@":Envelope/@xmlns:"+prefix] =
@"http://schemas.xmlsoap.org/soap/envelope/";
797 root[prefix+
@":Envelope/@xmlns:SOAP-ENC"] =
@"http://schemas.xmlsoap.org/soap/encoding/";
798 root[prefix+
@":Envelope/@xmlns:xsi"] =
@"http://www.w3.org/1999/XMLSchema-instance";
799 root[prefix+
@":Envelope/@xmlns:xsd"] =
@"http://www.w3.org/1999/XMLSchema";
801 root[prefix+
@":Envelope/"+prefix+
@":Body"] += body;
804 [req setHTTPMethod:
@"POST"];
806 req[
@"SOAPAction"] = action;
807 req[
@"Content-Type"] =
@"text/xml";
808 [req setHTTPBody:root.
data()];