Commits

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

Modified Files:
Tag: mm_fix
LibXML.pm
toString() works now more straight foreward

LibXML.xs
this adds a chunk of DTD functions. apart from createEntityReference() they are
not part of the DOM, but i think they are quite useful :)

+ createEntityReference
+ createExternalSubset
+ createInternalSubset
+ createDTD
+ internalSubset
+ externalSubset
+ setInternalSubset
+ setExternalSubset
[fix] cloneNode to clone DTDs, too

dom.c
[fix] domImportNode can *theoretically* import DTDs

perl-libxml-mm.c
+ PmmFreeNode() handles DTDs now (but can't really free them)

example/dtd.xml
added a foo entity, so i can test createEntityReference()

  • Participants
  • Parent commits 8f7a8ad
  • Branches mm_fix

Comments (0)

Files changed (5)

     my $class = shift;
     my %options = @_;
     my $self = bless \%options, $class;
-
     return $self;
 }
 
 
     my $retval = "";
 
+    my $intDTD;
+    if ( defined $XML::LibXML::skipDTD
+         and $XML::LibXML::skipDTD == 1 ) {
+        $intDTD = $self->removeInternalSubset;
+    }
+
     if ( defined $XML::LibXML::skipXMLDeclaration
          and $XML::LibXML::skipXMLDeclaration == 1 ) {
         foreach ( $self->childNodes ){
-            next if defined $XML::LibXML::skipDTD
-                    and $XML::LibXML::skipDTD == 1
-                    and $_->nodeType == XML::LibXML::XML_DTD_NODE();
-
             $retval .= $_->toString;
         }
     }
-    elsif ( defined $XML::LibXML::skipDTD
-         and $XML::LibXML::skipDTD == 1 ) {
-        # no chance to get the XML Decl from libxml2
-        $retval = '<?xml version="' . $self->version .'"';
-        my $standalone = $self->standalone;
-        my $encoding = $self->encoding;
-
-        $retval .= ' encoding="' . $encoding . '"' if defined $encoding;
-        $retval .= ' standalone="' .($standalone ? "yes" : "no" ). '"'
-          if defined $standalone && $standalone >= 0;
-        $retval .= "?>\n";
-        foreach ( $self->childNodes ){
-            next if $_->nodeType == XML::LibXML::XML_DTD_NODE();
-            $retval .= $_->toString(1);
-        }
-        $retval .= "\n";
-    }
     else {
         $retval =  $self->_toString($flag||0);
     }
+
+    if ( defined $intDTD ) {
+        $self->setInternalSubset( $intDTD );
+    }
+
     return $retval;
 }
 
         }
 
 
+
 SV*
 createDocument( CLASS, version="1.0", encoding=NULL )
         char * CLASS
     OUTPUT:
         RETVAL
 
+SV* 
+createInternalSubset( doc, Pname, extID, sysID )
+        SV * doc
+        SV * Pname
+        SV * extID
+        SV * sysID
+    PREINIT:
+        xmlDocPtr document = NULL;
+        xmlDtdPtr dtd = NULL;
+        xmlChar * name = NULL;
+        xmlChar * externalID = NULL;
+        xmlChar * systemID = NULL; 
+    CODE:
+        document = (xmlDocPtr)PmmSvNode( doc );
+        if ( document == NULL ) {
+            XSRETURN_UNDEF;   
+        }
+
+        name = Sv2C( Pname, NULL );
+        if ( name == NULL ) {
+            XSRETURN_UNDEF;
+        }  
+
+        externalID = Sv2C(extID, NULL);
+        systemID   = Sv2C(sysID, NULL);
+
+        dtd = xmlCreateIntSubset( document, name, externalID, systemID );
+
+        xmlFree(externalID);
+        xmlFree(systemID);
+        xmlFree(name);
+        if ( dtd ) {
+            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, SvPROXYNODE(doc) );
+        }
+        else {
+            XSRETURN_UNDEF;
+        }
+    OUTPUT:
+        RETVAL
+
+SV* 
+createExternalSubset( doc, Pname, extID, sysID )
+        SV * doc
+        SV * Pname
+        SV * extID
+        SV * sysID
+    PREINIT:
+        xmlDocPtr document = NULL;
+        xmlDtdPtr dtd = NULL;
+        xmlChar * name = NULL;
+        xmlChar * externalID = NULL;
+        xmlChar * systemID = NULL; 
+    CODE:
+        document = (xmlDocPtr)PmmSvNode( doc );
+        if ( document == NULL ) {
+            XSRETURN_UNDEF;   
+        }
+
+        name = Sv2C( Pname, NULL );
+        if ( name == NULL ) {
+            XSRETURN_UNDEF;
+        }  
+
+        externalID = Sv2C(extID, NULL);
+        systemID   = Sv2C(sysID, NULL);
+
+        dtd = xmlNewDtd( document, name, externalID, systemID );
+
+        xmlFree(externalID);
+        xmlFree(systemID);
+        xmlFree(name);
+        if ( dtd ) {
+            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, SvPROXYNODE(doc) );
+        }
+        else {
+            XSRETURN_UNDEF;
+        }
+    OUTPUT:
+        RETVAL
+
+SV* 
+createDTD( doc, Pname, extID, sysID )
+        SV * doc
+        SV * Pname
+        SV * extID
+        SV * sysID
+    PREINIT:
+        xmlDocPtr document = NULL;
+        xmlDtdPtr dtd = NULL;
+        xmlChar * name = NULL;
+        xmlChar * externalID = NULL;
+        xmlChar * systemID = NULL; 
+    CODE:
+        document = (xmlDocPtr)PmmSvNode( doc );
+        if ( document == NULL ) {
+            XSRETURN_UNDEF;   
+        }
+
+        name = Sv2C( Pname, NULL );
+        if ( name == NULL ) {
+            XSRETURN_UNDEF;
+        }  
+
+        externalID = Sv2C(extID, NULL);
+        systemID   = Sv2C(sysID, NULL);
+
+        dtd = xmlNewDtd( NULL, name, externalID, systemID );
+        dtd->doc = document;
+
+        xmlFree(externalID);
+        xmlFree(systemID);
+        xmlFree(name);
+        if ( dtd ) {
+            RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, SvPROXYNODE(doc) );
+        }
+        else {
+            XSRETURN_UNDEF;
+        }
+    OUTPUT:
+        RETVAL
 
 SV*
 createDocumentFragment( doc )
         RETVAL
 
 SV*
+createEntityReference( pdoc , pname )
+        SV * pdoc 
+        SV * pname
+    PREINIT:
+        xmlNodePtr newNode;
+        xmlDocPtr doc = (xmlDocPtr)PmmSvNode(pdoc);
+        xmlChar * name = Sv2C( pname, NULL );
+        ProxyNodePtr docfrag = NULL;        
+    CODE:
+        if ( name == NULL ) {
+            XSRETURN_UNDEF;
+        }
+        newNode = xmlNewReference( doc, name );
+        xmlFree(name);
+        if ( newNode == NULL ) {
+            XSRETURN_UNDEF;
+        }
+        docfrag = PmmNewFragment( doc );
+        domAppendChild( PmmNODE(docfrag), newNode );
+        RETVAL = PmmNodeToSv( newNode, docfrag );
+    OUTPUT:
+        RETVAL
+
+SV*
 createAttribute( pdoc, pname, pvalue=&PL_sv_undef )
         SV * pdoc
         SV * pname
     OUTPUT:
         RETVAL
 
+
+
 void 
 _setDocumentElement( dom , proxy )
         SV * dom
         RETVAL
 
 SV *
+externalSubset( doc )
+        SV * doc
+    PREINIT:
+        xmlDtdPtr dtd;
+    CODE:
+        if ( ((xmlDocPtr)PmmSvNode(doc))->extSubset == NULL ) {
+            XSRETURN_UNDEF;
+        }
+
+        dtd = ((xmlDocPtr)PmmSvNode(doc))->extSubset;
+        RETVAL = PmmNodeToSv((xmlNodePtr)dtd, SvPROXYNODE(doc));
+    OUTPUT:
+        RETVAL
+        
+SV *
+internalSubset( doc )
+        SV * doc
+    PREINIT:
+        xmlDtdPtr dtd;
+    CODE:
+        if ( ((xmlDocPtr)PmmSvNode(doc))->intSubset == NULL ) {
+            XSRETURN_UNDEF;
+        }
+
+        dtd = ((xmlDocPtr)PmmSvNode(doc))->intSubset;
+        RETVAL = PmmNodeToSv((xmlNodePtr)dtd, SvPROXYNODE(doc));
+    OUTPUT:
+        RETVAL
+
+void
+setExternalSubset( document, extdtd )
+        SV * document
+        SV * extdtd
+    PREINIT:
+        xmlDocPtr doc = NULL;
+        xmlDtdPtr dtd = NULL;
+        xmlDtdPtr olddtd = NULL;
+    CODE:
+        doc = (xmlDocPtr)PmmSvNode(document);
+        dtd = (xmlDtdPtr)PmmSvNode(extdtd);
+        if ( dtd && dtd != doc->extSubset ) {
+            if ( dtd->doc != doc ) {
+                croak( "can't import DTDs" );
+                domImportNode( doc, (xmlNodePtr) dtd,1);
+            }
+    
+            if ( dtd == doc->intSubset ) {
+                xmlUnlinkNode( (xmlNodePtr)dtd );
+                doc->intSubset = NULL;
+            }
+
+            olddtd = doc->extSubset;
+            if ( olddtd && olddtd->_private == NULL ) {
+                xmlFreeDtd( olddtd );
+            }
+            doc->extSubset = dtd;
+        }
+
+void
+setInternalSubset( document, extdtd )
+        SV * document
+        SV * extdtd
+    PREINIT:
+        xmlDocPtr doc = NULL;
+        xmlDtdPtr dtd = NULL;
+        xmlDtdPtr olddtd = NULL;
+    CODE:
+        doc = (xmlDocPtr)PmmSvNode(document);
+        dtd = (xmlDtdPtr)PmmSvNode(extdtd);
+        if ( dtd && dtd != doc->intSubset ) {
+            if ( dtd->doc != doc ) {
+                croak( "can't import DTDs" );
+                domImportNode( doc, (xmlNodePtr) dtd,1);
+            }
+    
+            if ( dtd == doc->extSubset ) {
+                doc->extSubset = NULL;
+            }
+
+            olddtd = doc->intSubset;
+            if( olddtd ) {
+                xmlReplaceNode( (xmlNodePtr)olddtd, (xmlNodePtr) dtd );
+                if ( olddtd->_private == NULL ) {
+                    xmlFreeDtd( olddtd );
+                }
+            }
+            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;
+                        }
+                    }
+                }
+            }
+            doc->intSubset = dtd;
+        }
+
+SV *
+removeInternalSubset( document ) 
+        SV * document
+    PREINIT:
+        xmlDocPtr doc = (xmlDocPtr)PmmSvNode(document);
+        xmlDtdPtr dtd = NULL;
+    CODE:
+        dtd = doc->intSubset;
+        if ( !dtd ) {
+            XSRETURN_UNDEF;   
+        }
+        xmlUnlinkNode( (xmlNodePtr)dtd );
+        doc->intSubset = NULL;
+        RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, SvPROXYNODE(document) );
+    OUTPUT:
+        RETVAL
+
+SV *
+removeExternalSubset( document ) 
+        SV * document
+    PREINIT:
+        xmlDocPtr doc = (xmlDocPtr)PmmSvNode(document);
+        xmlDtdPtr dtd = NULL;
+    CODE:
+        dtd = doc->extSubset;
+        if ( !dtd ) {
+            XSRETURN_UNDEF;   
+        }
+        doc->extSubset = NULL;
+        RETVAL = PmmNodeToSv( (xmlNodePtr)dtd, SvPROXYNODE(document) );
+    OUTPUT:
+        RETVAL
+
+SV *
 importNode( dom, node ) 
         SV * dom
         SV * node
         xmlNodePtr ret;
         ProxyNodePtr docfrag = NULL;
     CODE:
-        ret = xmlCopyNode( PmmSvNode(self), deep );
-        if (ret != NULL) {
-            docfrag = PmmNewFragment( ret->doc );
-            domAppendChild( PmmNODE(docfrag), ret );            
-            
-            RETVAL = PmmNodeToSv(ret, docfrag);
+        if ( PmmSvNode( self )->type == XML_DTD_NODE ) {
+            ret = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) PmmSvNode(self));
+            if (ret != NULL) {
+                RETVAL = PmmNodeToSv(ret, NULL);
+            }
+            else {
+                XSRETURN_UNDEF;
+            }
         }
         else {
-            XSRETURN_UNDEF;
-        }
+            ret = xmlCopyNode( PmmSvNode(self), deep );
+    
+            if (ret != NULL) {
+                docfrag = PmmNewFragment( ret->doc );
+                domAppendChild( PmmNODE(docfrag), ret );            
+            
+                RETVAL = PmmNodeToSv(ret, docfrag);
+            }
+            else {
+                XSRETURN_UNDEF;
+            }
+        }   
     OUTPUT:
         RETVAL
 
     if ( node && doc && node->doc != doc ) {
         if ( move ) {
             return_node = node;
-            xmlUnlinkNode( node );
+            if ( node->type != XML_DTD_NODE ) {
+                xmlUnlinkNode( node );
+            }
         }
         else {
-            return_node = xmlCopyNode( node, 1 );
+            if ( node->type == XML_DTD_NODE ) {
+                return_node = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) node);
+            }
+            else {
+                return_node = xmlCopyNode( node, 1 );
+            }
         }
         /* tell all children about the new boss */ 
 
     if( n != NULL ) {
         switch ( n->type ) {
         case XML_ATTRIBUTE_NODE:
+        case XML_ENTITY_DECL:
         case XML_TEXT_NODE:
         case XML_COMMENT_NODE:
         case XML_CDATA_SECTION_NODE:
             break;
         }
         
+
         if ( n->content != NULL ) {
             xs_warn(" dublicate content\n" );
             retval = xmlStrdup(n->content);
         }
         break;
     case XML_ELEMENT_NODE:
-        domNodeNormalizeList( node->properties );
+        domNodeNormalizeList( (xmlNodePtr) node->properties );
     case XML_ATTRIBUTE_NODE:
         return( domNodeNormalizeList( node->children ) );
         break;

File example/dtd.xml

 <!DOCTYPE doc [
 <!ELEMENT doc (#PCDATA)>
+<!ENTITY foo " test ">
 ]>
 <doc>This is a valid document !</doc>

File perl-libxml-mm.c

         if ( node->parent == NULL ) 
             xmlFreeProp( (xmlAttrPtr) node );
         break;
+    case XML_DTD_NODE:
+        if ( node->doc ) {
+            if ( node->doc->extSubset != (xmlDtdPtr)node 
+                 && node->doc->intSubset != (xmlDtdPtr)node ) {
+                xs_warn( "should free DTD\n");
+                node->doc = NULL;
+                // xmlFreeDtd( (xmlDtdPtr)node );
+            }
+        }
+        break;
     case XML_DOCUMENT_FRAG_NODE:
         xs_warn("XML_DOCUMENT_FRAG_NODE\n");
     default: