Page 1 of 2
DOM API No Modification Allowed Error
Posted: Tue Jan 23, 2007 5:00 pm
by thsoft
I'm using PHP 5's DOM API. My classes renderer methods return DOMDocumentFragment which are later inserted to the main DOMDocument by the page generator. But DOMNodes that are simply constructed and aren't created by a DOMDocument's createXXX() method can't be modified! I must have a workaround for this because:
1. Passing the DOMDocument as an argument to the renderer methods is awful because of performance and software design. Those classes don't have anything to do with my document.
2. Creating a temporary DOMDocument everytime and then finally copying its children, all these DOMDocumentFragments to the main DOMDocument is better not mentioned...
Anyway, in W3C's DOM Level 2 Recommendation, I didn't find anything about that nodes not attached to a document would be readonly. So may there be a solution so that I can build standalone nodes dynamically? Thx in advance!
Posted: Tue Jan 23, 2007 5:25 pm
by Kieran Huggins
Are you trying to modify them in the constructor?
Posted: Tue Jan 23, 2007 5:32 pm
by thsoft
Kieran Huggins wrote:Are you trying to modify them in the constructor?
No. The code is:
Code: Select all
function renderControl() {
$control = new DOMElement('input');
$control->setAttribute('type', 'text');
...
And I get the following error:
Code: Select all
Uncaught exception 'DOMException' with message 'No Modification Allowed Error'
Posted: Tue Jan 23, 2007 5:39 pm
by Kieran Huggins
I remember having the same problem as you - I just created one global temp document, then I'd create all new elements as a child of it. I think it has to do with inheritance in the DOM API. Will that work for you?
Code: Select all
$doc = $_SESSION['doc'] = new DOMDocument('1.0','UTF-8');
$test_element = $doc->createElement('test'); // instead of $test_element = $new DOMElement('test');
edit: I'm overloading the document's createElement method to append the child automatically..

Posted: Wed Jan 24, 2007 11:45 am
by thsoft
I understand the solution about the global document. But it still introduces ugly dependences. My self-standing components are not allowed to be in a need to know some global document, which they could even possibly modify. So I'm wondering about an own DOM-subset implementation...
Uh...
Posted: Sun Jan 28, 2007 7:39 am
by thsoft
I developed a not strictly DOM-conforming, but rather convenient XML API with parsing. But the performance results are tragical: the built-in API parses string to DOM tree 80-100 times and renders DOM tree to string 600-700 times faster then the homemade. Obviously it must be a precompiled C extension library, hence its incredible speed (parses a 200k document in 0.0186889 seconds...). So I will stick to it, and I'm thinking about an acceptable solution. I think every rendering routines will get a document. They don't know that, but it's only one temp doc maintained by the page generator. Either it will lock the document readonly, or it will return a new document the children of which are adopted from the temp one.
Posted: Sun Jan 28, 2007 1:00 pm
by Kieran Huggins
Try testing the performance of this:
http://www.php.net/manual/en/function.d ... eclass.php
As long as you're extending the existing compiled classes, most of your operations will remain nice and fast, but you should also gain the flexibility you're looking for.
Avoiding XML declaration
Posted: Mon Jan 29, 2007 6:06 pm
by thsoft
Kieran Huggins wrote:Try testing the performance of this:
http://www.php.net/manual/en/function.d ... eclass.php
As long as you're extending the existing compiled classes, most of your operations will remain nice and fast, but you should also gain the flexibility you're looking for.
Thx! A probable solution!
Anyway, I found another problem: I load the document template with DOMDocument::loadHTML(); otherwise I can't set the document type declaration which is obligatory. I process the document and get the result with DOMDocument::saveXML() in order to achieve proper XHTML output. But alas, this always puts the <?xml version="1.0" standalone="yes"?> XML declaration at the beginning, which I definitely want to avoid because of compatibility issues (eg. IE6 enters quirks mode when seeing it). Is there a way to have it omitted?
Posted: Mon Jan 29, 2007 6:09 pm
by Ambush Commander
I say just str_replace it out. Since you're guarding against a browser quirk, I don't see any reason why not to be a little hacky about it. You could even sniff the browser user-agent and only apply the change when it's IE.
Posted: Mon Jan 29, 2007 6:28 pm
by Kieran Huggins
or transform the xml to proper xhtml, without the xml declaration. str_replace is likely faster, but xslt is more flexible. It will also allow you to template the output.
DOM DocumentTraversal
Posted: Tue Jan 30, 2007 1:23 pm
by thsoft
I'm really fed up with IE, but that's another story. Yes, the preg_replace version is hacky, and the XSLT is a bit overkill, because I am gonna do the "templating" with the DOM document traversal method - thus, I can invoke PHP modules with XML tags. (Much flexible than Smarty or other templating engines, and with the built-in DOM API, it's very fast.) But the PHP DOM API doesn't contain the DOM Level 2 Traversal implementation. Does anyone know a 3rd party API for this?
(Anyway, I made a mistake: DOMDocument::loadXML() recognizes doctype successfully, and it is well faster than loadHTML().)
Posted: Tue Jan 30, 2007 4:15 pm
by Ambush Commander
Erm, what are you going to do when you need a conditional? Or a loop? Or anything remotely complex? I strongly advise you reconsider your view that XSLT is overkill, it can work as a templating language although that's not it's primary focus.
Posted: Tue Jan 30, 2007 4:55 pm
by thsoft
I meant XSLT is overkill only for omitting XML declaration.

It is an advanced way for transformation, but I would like a templating solution.
Conditional statements and loops will be also XML elements. Every custom XML element has a PHP processor function which returns a document fragment with which its corresponding element will be replaced. Of course, these processor functions get the elements attributes and children for processing.
Posted: Tue Jan 30, 2007 5:11 pm
by Kieran Huggins
If you're using PHP to do your transform you can make new XSLT functions that map to existing PHP functions - even user functions!
Posted: Tue Jan 30, 2007 6:06 pm
by Ambush Commander
See, you're reinventing the wheel. XSLT already does all this. If you want, I can make an example XSLT file that acts like a templating solution.