Commits

ph...@9ae0c189-cd1f-4510-a509-f4891f5cf20d  committed fa4c571

Modified Files:
Tag: mm_fix
LibXML.pm LibXML.xs
[fix] Document::toString() works correctly now
+ appendText() (and its alias appendTextNode())
+ appendTextNode()
+ appendWellBalancedChunk()
this function loads a local parser and parses the string in the
perl level instead of re building the parser on C level
+ some compatibility aliases
o internal subsets are handled better now

(most tests pass now)

typemap
? no idea

lib/XML/LibXML/SAX/Builder.pm
lib/XML/LibXML/SAX/Parser.pm
o updated so official DOM functions are used instead of the stuff
we created

t/06elements.t
+ appendText() and appendTextChild() tests

t/20extras.t
o whitespaces

  • Participants
  • Parent commits 064c60b
  • Branches mm_fix

Comments (0)

Files changed (6)

 
 @ISA = qw(DynaLoader Exporter);
 
+$XML::LibXML::skipDTD            = 0;
+$XML::LibXML::skipXMLDeclaration = 0;
+$XML::LibXML::setTagCompression  = 0;
+
 bootstrap XML::LibXML $VERSION;
 
 @EXPORT = qw( XML_ELEMENT_NODE
 
     my $retval = "";
 
-    my $intDTD;
-    # if ( defined $XML::LibXML::skipDTD
-    #     and $XML::LibXML::skipDTD == 1 ) {
-    #    $intDTD = 1;
-    #    $self->setExternalSubset( $self->internalSubset );
-    #}
-
     if ( defined $XML::LibXML::skipXMLDeclaration
          and $XML::LibXML::skipXMLDeclaration == 1 ) {
         foreach ( $self->childNodes ){
+            next if $_->nodeType == XML::LibXML::XML_DTD_NODE()
+                    and $XML::LibXML::skipDTD;
             $retval .= $_->toString;
         }
     }
         $retval =  $self->_toString($flag||0);
     }
 
-    # if ( defined $intDTD ) {
-    #    $self->setInternalSubset( $self->externalSubset );
-    # }
-
     return $retval;
 }
 
     return wantarray ? @nodes : XML::LibXML::NodeList->new(@nodes);
 }
 
+sub appendWellBalancedChunk {
+    my ( $self, $chunk ) = @_;
+
+    my $local_parser = XML::LibXML->new();
+    my $frag = $local_parser->parse_xml_chunk( $chunk );
+
+    $self->appendChild( $frag );
+}
+
 1;
 
 package XML::LibXML::Text;
         int len=0;
         SV* internalFlag = NULL;
         int oldTagFlag = xmlSaveNoEmptyTags;
+        xmlDtdPtr intSubset = NULL;
     CODE:
         real_dom = (xmlDocPtr)PmmNODE(SvPROXYNODE(self));
         internalFlag = get_sv("XML::LibXML::setTagCompression", 0);
             xmlSaveNoEmptyTags = SvTRUE(internalFlag);
         }
 
+        internalFlag = get_sv("XML::LibXML::skipDTD", 0);
+        if ( internalFlag && SvTRUE(internalFlag) ) {
+            intSubset = xmlGetIntSubset( real_dom );
+            if ( intSubset )
+                xmlUnlinkNode( (xmlNodePtr)intSubset );
+        }
+
         if ( format <= 0 ) {
             # warn( "use no formated toString!" );
             xmlDocDumpMemory(real_dom, &result, &len);
             xmlIndentTreeOutput = t_indent_var;
         }
 
+        if ( intSubset != NULL ) {
+            if (real_dom->children == NULL)
+                 xmlAddChild((xmlNodePtr) real_dom, (xmlNodePtr) intSubset);
+            else
+                xmlAddPrevSibling(real_dom->children, (xmlNodePtr) intSubset);
+        }
+
         xmlSaveNoEmptyTags = oldTagFlag;
 
     	if (result == NULL) {
         xmlCharEncodingHandlerPtr handler = NULL;
         SV* internalFlag = NULL;
         int oldTagFlag = xmlSaveNoEmptyTags;
+        xmlDtdPtr intSubset = NULL;
+        xmlDocPtr doc = (xmlDocPtr)PmmSvNode( self );
     CODE:
         internalFlag = get_sv("XML::LibXML::setTagCompression", 0);
         if( internalFlag ) {
             xmlSaveNoEmptyTags = SvTRUE(internalFlag);
         }
 
+        internalFlag = get_sv("XML::LibXML::skipDTD", 0);
+        if ( internalFlag && SvTRUE(internalFlag) ) {
+            intSubset = xmlGetIntSubset( doc );
+            if ( intSubset )
+                xmlUnlinkNode( (xmlNodePtr)intSubset );
+        }
+
         xmlRegisterDefaultOutputCallbacks();
         encoding = ((xmlDocPtr) PmmSvNode(self))->encoding;
         if ( encoding != NULL ) {
                                           filehandler,
                                           handler ); 
         RETVAL =xmlSaveFormatFileTo( buffer, 
-                                     (xmlDocPtr)PmmSvNode(self),
+                                     doc,
                                      encoding,
                                      format);
+        if ( intSubset != NULL ) {
+            if (doc->children == NULL)
+                xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) intSubset);
+            else
+                xmlAddPrevSibling(doc->children, (xmlNodePtr) intSubset);
+        }
+
         xmlSaveNoEmptyTags = oldTagFlag;
         xmlOutputBufferClose( buffer );
     OUTPUT:
         systemID   = Sv2C(sysID, NULL);
 
         dtd = xmlCreateIntSubset( document, name, externalID, systemID );
-
         xmlFree(externalID);
         xmlFree(systemID);
         xmlFree(name);
                 doc->extSubset = NULL;
             }
 
-            olddtd = doc->intSubset;
+            olddtd = xmlGetIntSubset( doc );
             if( olddtd ) {
                 xmlReplaceNode( (xmlNodePtr)olddtd, (xmlNodePtr) dtd );
                 if ( olddtd->_private == NULL ) {
                 }
             }
             else {
-                /* there is no setinternal subset function in libxml :/ */
-                if (doc->children == NULL) {
-                    doc->children = (xmlNodePtr) dtd;
-                    doc->last = (xmlNodePtr) dtd;
-                } else {
-                    if (doc->type == XML_HTML_DOCUMENT_NODE) {
-                        xmlNodePtr prev;
-
-                        prev = doc->children;
-                        prev->prev = (xmlNodePtr) dtd;
-                        dtd->next = prev;
-                        doc->children = (xmlNodePtr) dtd;
-                    } else {
-                        xmlNodePtr next;
-
-                        next = doc->children;
-                        while ((next != NULL)
-                               && (next->type != XML_ELEMENT_NODE))
-                            next = next->next;
-                        if (next == NULL) {
-                            dtd->prev = doc->last;
-                            dtd->prev->next = (xmlNodePtr) dtd;
-                            dtd->next = NULL;
-                            doc->last = (xmlNodePtr) dtd;
-                        } else {
-                            dtd->next = next;
-                            dtd->prev = next->prev;
-                            if (dtd->prev == NULL)
-                                doc->children = (xmlNodePtr) dtd;
-                            else
-                                dtd->prev->next = (xmlNodePtr) dtd;
-                            next->prev = (xmlNodePtr) dtd;
-                        }
-                    }
-                }
+                if (doc->children == NULL)
+                    xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
+                else
+                    xmlAddPrevSibling(doc->children, (xmlNodePtr) dtd);
             }
             doc->intSubset = dtd;
         }
         xmlDocPtr doc = (xmlDocPtr)PmmSvNode(document);
         xmlDtdPtr dtd = NULL;
     CODE:
-        dtd = doc->intSubset;
+        dtd = xmlGetIntSubset(doc);
         if ( !dtd ) {
             XSRETURN_UNDEF;   
         }
         XML::LibXML::Attr::getValue  = 2
         XML::LibXML::Text::data      = 3
         XML::LibXML::Node::getValue  = 4
+        XML::LibXML::Node::getData   = 5
     PREINIT:
         xmlNodePtr node;
         xmlChar * content = NULL;
 parentNode( self )
         SV *self
     ALIAS:
-        XML::LibXML::Attr::ownerElement = 1
+        XML::LibXML::Attr::ownerElement  = 1
+        XML::LibXML::Node::getParentNode = 2
     CODE:
         RETVAL = PmmNodeToSv( PmmSvNode(self)->parent,
                               PmmOWNERPO( SvPROXYNODE(self) ) ); 
 SV*
 firstChild( self )
         SV *self
+    ALIAS:
+        getFirstChild = 1
     CODE:
         RETVAL = PmmNodeToSv( PmmSvNode(self)->children,
                               PmmOWNERPO( SvPROXYNODE(self) ) ); 
 SV*
 lastChild( self )
         SV *self
+    ALIAS:
+        getLastChild = 1
     CODE:
         RETVAL = PmmNodeToSv( PmmSvNode(self)->last,
                               PmmOWNERPO( SvPROXYNODE(self) ) ); 
             xmlFree(nsURI);
             XSRETURN_UNDEF;
         }
-        if ( !nsURI ) {
-            xmlFree(name);
-            XSRETURN_UNDEF;
-        }
         
         ret = xmlGetNsProp( node, name, nsURI );
         xmlFree( name );
         xmlChar * value = NULL;
         xmlNsPtr ns;
     CODE:
-        if ( !nsURI ) {
-            XSRETURN_UNDEF;
-        }
-
-        ns = xmlSearchNsByHref( node->doc, node, nsURI );
-        if ( !ns ) {
-            // create new ns
-            xmlChar * localname;
-            xmlChar * prefix;
-
-            name  = nodeSv2C( attr_name, node );
-            if ( ! name ) {
-                xmlFree(nsURI);
+        if ( nsURI && xmlStrlen(nsURI) ) {
+            ns = xmlSearchNsByHref( node->doc, node, nsURI );
+            if ( !ns ) {
+                // create new ns
+                xmlChar * localname;
+                xmlChar * prefix;
+
+                name  = nodeSv2C( attr_name, node );
+                if ( ! name ) {
+                    xmlFree(nsURI);
+                    XSRETURN_UNDEF;
+                }
+                localname = xmlSplitQName2(name, &prefix); 
+            
+                xmlFree( name );
+                name = localname;
+            
+                ns = xmlNewNs(node, nsURI , prefix );
+                xmlFree( prefix );
+            }
+            else {
+                xmlChar * localname;
+                xmlChar * prefix;
+
+                name  = nodeSv2C( attr_name, node );
+                if (!name) {
+                    xmlFree(nsURI);
+                    XSRETURN_UNDEF;
+                }
+                localname = xmlSplitQName2(name, &prefix); 
+                xmlFree(prefix);
+                xmlFree(name);
+                name = localname;
+            }
+            xmlFree(nsURI);
+
+            value = nodeSv2C( attr_value, node );
+            if (!value) {
+                xmlFree(name);
                 XSRETURN_UNDEF;
             }
-            localname = xmlSplitQName2(name, &prefix); 
-            
-            xmlFree( name );
-            name = localname;
-            
-            ns = xmlNewNs(node, nsURI , prefix );
-            xmlFree( prefix );
+        
+            xmlSetNsProp( node, ns, name, value );
         }
         else {
-            xmlChar * localname;
-            xmlChar * prefix;
-
             name  = nodeSv2C( attr_name, node );
             if (!name) {
                 xmlFree(nsURI);
                 XSRETURN_UNDEF;
             }
-            localname = xmlSplitQName2(name, &prefix); 
-            xmlFree(prefix);
-            xmlFree(name);
-            name = localname;
+            value = nodeSv2C( attr_value, node ); 
+            xmlSetProp( node, name, value );            
         }
-        xmlFree(nsURI);
-
-        value = nodeSv2C( attr_value, node );
-        if (!value) {
-            xmlFree(name);
-            XSRETURN_UNDEF;
-        }
-        
-        xmlSetNsProp( node, ns, name, value );
         xmlFree( name );
         xmlFree( value );
 
     OUTPUT:
         RETVAL
 
+void
+appendText( self, string )
+        SV * self
+        SV * string
+    ALIAS:
+        appendTextNode = 1
+    PREINIT:
+        xmlNodePtr node   = PmmSvNode( self );
+        xmlChar * content = nodeSv2C( string, node );
+    INIT:
+        if ( content == NULL ) {
+            XSRETURN_UNDEF;
+        }
+        if ( xmlStrlen(content) == 0 ) {
+            xmlFree( content );
+            XSRETURN_UNDEF;
+        }
+    CODE:
+        xmlNodeAddContent( node, content );
+        xmlFree(content);
+
+void
+appendTextChild( self, strname, strcontent=&PL_sv_undef, nsURI=&PL_sv_undef )
+        SV * self
+        SV * strname
+        SV * strcontent
+        SV * nsURI
+    PREINIT:
+        xmlNodePtr node   = PmmSvNode( self );
+        xmlChar * name    = nodeSv2C( strname, node );
+        xmlChar * content = NULL;
+        xmlChar * encstr  = NULL;
+    INIT:
+        if ( name == NULL ) {
+            XSRETURN_UNDEF;
+        }
+        if ( xmlStrlen(name) == 0 ) {
+            xmlFree(name);
+            XSRETURN_UNDEF;
+        }
+    CODE: 
+        content = nodeSv2C(strcontent, node);
+        if ( content &&  xmlStrlen( content ) == 0 ) {
+            xmlFree(content);
+            content=NULL;
+        }
+        else if ( content ) {
+            encstr = xmlEncodeEntitiesReentrant( node->doc, content );
+            xmlFree(content);
+        }
+
+        xmlNewChild( node, NULL, name, encstr );
+
+        if ( encstr ) 
+            xmlFree(encstr);
+        xmlFree(name);
+
+
 MODULE = XML::LibXML         PACKAGE = XML::LibXML::Text
 
 SV *
     ALIAS:
         value = 1
         nodeValue = 2
+        getData = 3
+        getNamespaceURI = 4
     PREINIT:
         xmlNsPtr ns = (xmlNsPtr)SvIV(SvRV(self));
         xmlChar * href;
 localname(self)
         SV * self
     ALIAS:
-        name = 2
+        name = 1
+        getLocalName = 2
+        getName = 3 
     PREINIT:
         xmlNsPtr ns = (xmlNsPtr)SvIV(SvRV(self));
         xmlChar * prefix;

File lib/XML/LibXML/SAX/Parser.pm

     }
     elsif ($node_type == XML_TEXT_NODE || $node_type == XML_CDATA_SECTION_NODE) {
         # warn($node->getData . "\n");
-        $self->characters( { Data => $node->getData } );
+        $self->characters( { Data => $node->nodeValue } );
     }
     elsif ($node_type == XML_ELEMENT_NODE) {
         # warn("<" . $node->getName . ">\n");
     my $attribs = {};
     my @ns_maps;
 
-    foreach my $attr ($element->getAttributes) {
+    foreach my $attr ($element->attributes) {
         my $key;
         # warn("Attr: $attr -> ", $attr->getName, " = ", $attr->getData, "\n");
         if ($attr->isa('XML::LibXML::Namespace')) {
             # TODO This needs fixing modulo agreeing on what
             # is the right thing to do here.
             my ($localname, $p);
-            if (my $prefix = $attr->getLocalName) {
-                $key = "{" . $attr->getNamespaceURI . "}" . $prefix;
+            if (my $prefix = $attr->prefix) {
+                $key = "{" . $attr->href . "}" . $prefix;
                 $localname = $prefix;
                 $p = "xmlns";
             }
             else {
-                $key = $attr->getName;
+                $key = $attr->name;
                 $localname = $key;
                 $p = '';
             }
             $attribs->{$key} =
                 {
-                    Name => $attr->getName,
-                    Value => $attr->getData,
-                    NamespaceURI => $attr->getNamespaceURI,
+                    Name => $attr->prefix,
+                    Value => $attr->href,
+                    NamespaceURI => $attr->href,
                     Prefix => $p,
                     LocalName => $localname,
                 };
             push @ns_maps, $attribs->{$key};
         }
         else {
-            my $ns = $attr->getNamespaceURI || '';
-            $key = "{$ns}".$attr->getLocalName;
+            my $ns = $attr->namespaceURI || '';
+            $key = "{$ns}".$attr->localname;
             $attribs->{$key} =
                 {
-                    Name => $attr->getName,
-                    Value => $attr->getData,
-                    NamespaceURI => $attr->getNamespaceURI,
-                    Prefix => $attr->getPrefix,
-                    LocalName => $attr->getLocalName,
+                    Name => $attr->name,
+                    Value => $attr->value,
+                    NamespaceURI => $attr->namespaceURI,
+                    Prefix => $attr->prefix,
+                    LocalName => $attr->localname,
                 };
         }
         # use Data::Dumper;
     }
 
     my $node = {
-        Name => $element->getName,
+        Name => $element->nodeName,
         Attributes => $attribs,
-        NamespaceURI => $element->getNamespaceURI,
-        Prefix => $element->getPrefix,
-        LocalName => $element->getLocalName,
+        NamespaceURI => $element->namespaceURI,
+        Prefix => $element->prefix,
+        LocalName => $element->localname,
     };
 
     foreach my $ns (@ns_maps) {

File t/06elements.t

 use strict;
 use warnings;
 
-BEGIN { plan tests => 45 };
+
+BEGIN { plan tests => 51 };
 use XML::LibXML;
 
 my $foo       = "foo";
 
     ok( $t2->parentNode, undef);
     ok( $t3->parentNode, undef);
-}
+}
+
+
+print "# 5. XML::LibXML extensions\n";
+{
+    my $plainstring = "foo";
+    my $stdentstring= "$foo & this";
+    
+    my $doc = XML::LibXML::Document->new();
+    my $elem = $doc->createElement( $foo );
+    $doc->setDocumentElement( $elem );
+    
+    $elem->appendText( $plainstring );
+    ok( $elem->string_value , $plainstring );
+
+    $elem->appendText( $stdentstring );
+    ok( $elem->string_value , $plainstring.$stdentstring );
+
+    $elem->appendTextChild( "foo");
+    $elem->appendTextChild( "foo" => "foo&bar" );
+
+    my @cn = $elem->childNodes;
+    ok( @cn );
+    ok( scalar(@cn), 3 );
+    ok( !$cn[1]->hasChildNodes);
+    ok( $cn[2]->hasChildNodes);
+}

File t/20extras.t

 }
 
 {
-#    local $XML::LibXML::skipDTD = 1;
+    local $XML::LibXML::skipDTD = 1;
     my $doc = $parser->parse_file( "example/dtd.xml" );
     ok($doc);
     my $test = "<?xml version=\"1.0\"?>\n<doc>This is a valid document !</doc>\n";
 TYPEMAP
 const char *                T_PV
-xmlDocPtr                   PROXY_OBJECT
-xmlNodePtr                  PROXY_OBJECT
-xmlNsPtr                    O_OBJECT
 xmlParserCtxtPtr            O_OBJECT
-xmlDtdPtr                   PROXY_OBJECT
 xmlNodeSetPtr               O_OBJECT
-ProxyObject *               O_OBJECT
 perlxmlParserObjectPtr      O_OBJECT
 
 
             XSRETURN_UNDEF;
     }
 
-PROXY_OBJECT
-    if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
-            $var = ($type)(((ProxyObject *)SvIV((SV*)SvRV( $arg )))->object);
-    else{
-            warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
-            XSRETURN_UNDEF;
-    }
-
 OUTPUT
 
 # The Perl object is blessed into 'CLASS', which should be a
 O_OBJECT
         sv_setref_pv( $arg, (char *)CLASS, (void*)$var );
 
-PROXY_OBJECT
-        sv_setref_pv( $arg, (char *)CLASS, (void*)$var );