added Info.plist
[TestXSLT.git] / libsablot / src / engine / sdom.cpp
1 /* 
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  * 
12  * The Original Code is the Sablotron XSLT Processor.
13  * 
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  * 
18  * Contributor(s):
19  * 
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable 
23  * instead of those above.  If you wish to allow use of your 
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32
33 /* sdom.cpp */
34
35 #define SablotAsExport
36 #include "sdom.h"
37
38 #ifdef ENABLE_DOM
39
40 #include "base.h"
41 #include "verts.h"
42 #include "tree.h"
43 #include "context.h"
44 #include "guard.h"
45
46 #define getTmpList(v) (toV(v) -> getOwner().tmpList)
47
48 char* SDOM_ExceptionMsg[] = 
49 {
50     // SDOM_OK
51     (char *) "OK",
52     
53     // SDOM_INDEX_SIZE_ERR 1
54     (char *) "list index out of bounds",
55     
56     // SDOM_DOMSTRING_SIZE_ERR 2
57     (char *) "invalid size of string",
58
59     // SDOM_HIERARCHY_REQUEST_ERR 3
60     (char *) "hierarchy request error",
61     
62     // SDOM_WRONG_DOCUMENT_ERR 4
63     (char *) "node used in a document that did not create it",
64     
65     // SDOM_INVALID_CHARACTER_ERR 5
66     (char *) "invalid character in string",
67
68     // SDOM_NO_DATA_ALLOWED_ERR 6 
69     (char *) "data not allowed",
70
71     // SDOM_NO_MODIFICATION_ALLOWED_ERR 7
72     (char *) "modification not allowed",
73     
74     // SDOM_NOT_FOUND_ERR 8
75     (char *) "reference to a non-existent node",
76
77     // SDOM_NOT_FOUND_ERR 9
78     (char *) "functionality not supported",
79
80     // SDOM_INUSE_ATTRIBUTE_ERR 10
81     (char *) "attribute is inuse",
82
83     // SDOM_NOT_FOUND_ERR 10
84     (char *) "attribute is inuse",
85         
86     // SDOM_INVALID_STATE_ERR 11
87     (char *) "invalid state",
88
89     // SDOM_SYNTAX_ERR 12
90     (char *) "syntax error",
91
92     // SDOM_INVALID_MODIFICATION_ERR 13
93     (char *) "invalid modification",
94
95     // SDOM_NAMESPACE_ERR 14
96     (char *) "namespace error",
97
98     // SDOM_INVALID_ACCESS_ERR 15
99     (char *) "invalid access",
100
101     // INVALID_NODE_TYPE
102     (char *) "invalid node type",
103     
104     // SDOM_QUERY_PARSE_ERR
105     (char *) "query parsing error",
106     
107     // SDOM_QUERY_EXECUTION_ERR
108     (char *) "query execution error",
109     
110     // SDOM_NOT_OK
111     (char *) "general exception"
112 };
113
114 #define SDOM_Err(SITUA, CODE) { SIT( SITUA ).setSDOMExceptionCode( CODE );\
115     SIT( SITUA ).message(\
116     MT_ERROR, E2_SDOM, CODE, SDOM_ExceptionMsg[CODE]); return CODE; }
117
118 #define SE(statement) {SDOM_Exception code__ = statement; \
119     if (code__) return code__;}
120     
121 #define SIT(PTR) (*(Situation*)PTR)
122
123 #define isXMLNS_(qn, resolver) \
124     (qn.getPrefix() == resolver -> getOwner().stdPhrase(PHRASE_XMLNS) || \
125         (qn.getPrefix() == UNDEF_PHRASE && \
126              qn.getLocal() == resolver -> getOwner().stdPhrase(PHRASE_XMLNS)))
127
128 //
129 //    globals
130 //
131
132 SDOM_NodeCallback* theDisposeCallback = NULL;
133 #define ownerDoc(NODE) ( &(toV(NODE)->getOwner().getRoot()) )
134
135 char* SDOM_newString(const Str& strg)
136 {
137     int len = strg.length();
138     char *p = new char[len + 1];
139     strcpy(p, (char*)(const char*)strg);
140     p[len] = 0;
141     return p;
142 }
143  
144 //_JP_ v
145 // helper functions for namespace handling
146 SDOM_Exception ___SDOM_swallowParentNSrec(SablotSituation s, SDOM_Node n, Tree* t, NSList* parentNs)
147 {
148   // inherits from parentNs to begin of n->namespaces with respect to scoping
149   // do it recursively for all child elements
150     if ( isElement(toV(n)) ) {
151       NSList* currentNs   = &(toE(n) -> namespaces);
152       NmSpace* nm;
153       const int imax = parentNs->number() - 1;
154       for (int i = imax; i >= 0; i--) {
155           nm = toNS((*parentNs)[i]);
156           if (currentNs -> findNdx(nm -> prefix) == -1) {
157             nm = new(&(NZ(t) -> getArena())) NmSpace(*t, nm -> prefix, nm -> uri, 
158                                                      NSKIND_PARENT);
159             currentNs -> append(toV(nm));
160             nm -> parent = toV(n);
161           };
162       };
163       //zero in args => all appended namespaces will have kind == NSKIND_PARENT
164       //parentNs->giveCurrent(SIT(s), *currentNs, t, 0);
165       SDOM_Node checkedNode;
166       SE( SDOM_getFirstChild(s, n, &checkedNode) );
167       while (checkedNode) {
168         SE( ___SDOM_swallowParentNSrec(s, checkedNode, t, currentNs) );
169         SE( SDOM_getNextSibling(s, checkedNode, &checkedNode) );
170       };
171     };
172     return SDOM_OK;
173 }
174
175 SDOM_Exception __SDOM_swallowParentNS(SablotSituation s, SDOM_Node n)
176 {
177   // inherits from parent's NSList to begin of n->namespaces with respect to scoping
178   // do it recursively for all child elements
179     if ( n && isElement(toV(n)) && toE(n) -> parent ) {
180       NSList* parentNs = &(toE(toE(n) -> parent) -> namespaces);
181       Tree* t = toTree( n );
182       SE( ___SDOM_swallowParentNSrec(s, n, t, parentNs) );
183     };
184     return SDOM_OK;
185 }
186
187 SDOM_Exception __SDOM_dropParentNS(SablotSituation s, SDOM_Node n)
188 {
189   // removes inherited namespaces from n->namespaces 
190   // and from all child elements recursively
191     if ( n && isElement(toV(n)) ) {
192       NSList *checkedNs = &(toE(n) -> namespaces);
193       NmSpace *nm;
194       const int imax = checkedNs->number() - 1;
195       for (int i = imax; i >= 0; i--) { 
196         nm = toNS((*checkedNs)[i]);
197         if ( nm -> usageCount == 0 && nm -> kind == NSKIND_PARENT ) {
198           checkedNs->rm(i);
199           nm -> parent = NULL;
200           getTmpList(toE(n)).append(nm);
201         };
202       };
203       SDOM_Node checkedNode;
204       SE( SDOM_getFirstChild(s, n, &checkedNode) );
205       while (checkedNode) {
206         SE( __SDOM_dropParentNS(s, checkedNode) );
207         SE( SDOM_getNextSibling(s, checkedNode, &checkedNode) );
208       };
209     };
210     return SDOM_OK;
211 }
212
213 SDOM_Exception __SDOM_refreshNS(SablotSituation s, SDOM_Node n, NmSpace* nmspace)
214 {
215   // appends or changes nmspace in all child elements recursively
216   // with respect to scoping
217     SDOM_Node checkedNode;
218     Tree *t;
219     NmSpace *nm;
220     SE( SDOM_getFirstChild(s, n, &checkedNode) );
221     while (checkedNode) {
222       if ( isElement(checkedNode) ) {
223           nm = toE(checkedNode) -> namespaces.find(nmspace -> prefix);
224           if ( nm ) {
225               if ( nm -> usageCount == 0 && nm -> kind == NSKIND_PARENT ) {
226                   nm -> uri = nmspace -> uri;
227                   SE( __SDOM_refreshNS(s, checkedNode, nmspace) );
228               };
229           } else {
230               //t = toTree(ownerDoc(toE(n)));
231               t = &(toE(n) -> getOwner());
232               nm = new(&(t -> getArena())) NmSpace(*t, nmspace -> prefix, 
233                                                        nmspace -> uri, 
234                                                        NSKIND_PARENT);
235               toE(checkedNode) -> namespaces.append(nm);
236               nm -> setParent(toE(checkedNode));
237               SE( __SDOM_refreshNS(s, checkedNode, nmspace) );
238           };
239       };
240       SE( SDOM_getNextSibling(s, checkedNode, &checkedNode) );
241     };    
242     return SDOM_OK;
243 }
244
245 SDOM_Exception __SDOM_canChangeUriNS(SablotSituation s, SDOM_Node n, NmSpace* nmspace, const SDOM_char *uri)
246 {
247   // order of tests has meaning
248   if ( !n || nmspace->usageCount == 0 ) 
249     // namespace without parent is changeable
250     // not used namespace is changeable
251       return SDOM_OK;
252   
253   Str olduri = toV(nmspace)->getOwner().expand(nmspace->uri);
254   if ( !strcmp((char*)olduri,(char*)uri) ) 
255       return SDOM_OK;// no change will be done
256
257   return SDOM_NAMESPACE_ERR;
258 }
259
260
261 SDOM_Exception __SDOM_touchNS(SablotSituation s, SDOM_Node n, Phrase prefix, Phrase uri, NsKind kind, unsigned int maxUsageCount)
262 {
263   //appends or changes n.namespaces to push prefix:uri into scope
264   //potentially refreshes childrens' namespaces
265   //suppose if kind == NSKIND_DECLARED then nm will NOT be immediatelly used
266   //suppose if kind == NSKIND_PARENT then nm will be immediatelly used 
267   NmSpace *nm = toE(n)->namespaces.find(prefix);
268   if (nm) {
269     //nm->prefix == prefix
270     if (nm->uri == uri) {
271       if (kind == NSKIND_PARENT) nm -> usageCount++;
272       else nm -> kind = kind;
273     } else {
274       if ( kind == NSKIND_PARENT ) {
275         if (nm -> kind == NSKIND_PARENT && nm -> usageCount <= maxUsageCount) {
276           nm -> uri = uri;
277           return __SDOM_refreshNS(s, n, nm);
278         } else {
279           return SDOM_NAMESPACE_ERR;//_JP_ not in spec - namespace collision
280         };
281       } else {
282         if (nm -> usageCount <= maxUsageCount) {
283           nm -> kind = kind;
284           nm -> uri = uri;
285           return __SDOM_refreshNS(s, n, nm);
286         } else {
287           return SDOM_NAMESPACE_ERR;//_JP_ not in spec - namespace collision
288         };      
289       };
290     };
291   } else {
292     //nm with prefix not exists
293     //!!chybka
294         //Tree *auxt = NZ(toTree(ownerDoc(toE(n))));
295         Tree *auxt = &(toE(n) -> getOwner());
296     nm = new(&(auxt -> getArena())) 
297             NmSpace(toE(n) -> getOwner(),prefix, uri, kind);
298     if (kind == NSKIND_PARENT) nm -> usageCount = 1;
299     toE(n) -> namespaces.append(nm);
300     toV(nm) -> setParent(toE(n));
301   };
302   return SDOM_OK;
303 }
304
305
306 SDOM_Exception __SDOM_touchNSByChar(SablotSituation s, SDOM_Node n, SDOM_char* prefix, SDOM_char* uri, NsKind kind, int maxUsageCount)
307 {
308   //appends or changes n.namespaces to push prefix:uri into scope
309   //potentially refreshes childrens' namespaces
310   Phrase ph_prefix = prefix && strcmp((char*)prefix,"xmlns") ? toE(ownerDoc(toE(n)))->dict().insert((const char*)prefix) : UNDEF_PHRASE;
311   Phrase ph_uri = uri ? toE(ownerDoc(toE(n)))->dict().insert((const char*)uri) : UNDEF_PHRASE;
312   return __SDOM_touchNS(s, n, ph_prefix, ph_uri, kind, maxUsageCount);
313 }
314
315
316 //_JP_ ^
317
318
319 SDOM_Exception SDOM_createElement(SablotSituation s, SDOM_Document d, SDOM_Node *pn, const SDOM_char *tagName)
320 {
321     QName q;
322     //try to find the document element
323     Element *e = NULL;
324     for (int i = 0; i < toRoot(d) -> contents.number(); i++)
325       {
326         if (isElement(toRoot(d) -> contents[i]))
327           {
328             e = toE(toRoot(d) -> contents[i]);
329             break;
330           }
331       }
332     if (!e) e = toRoot(d);
333
334     e -> setLogical(SIT(s), q, tagName, TRUE);
335     *pn = new(&(toTree(d) -> getArena())) Element(*toTree(d), q);
336     //_TH_ v
337     getTmpList(d).append(*pn);
338     //_TH_ ^
339     return SDOM_OK;
340 }
341
342 //_JP_ v
343 SDOM_Exception SDOM_createElementNS(SablotSituation s, SDOM_Document d, SDOM_Node *pn, const SDOM_char *uri, const SDOM_char *qName)
344 {
345     if ( !isValidQName((char*)qName) )
346         return SDOM_INVALID_CHARACTER_ERR;
347
348     Str prefix = Str();
349     const char *colon = strchr((char*)qName,':');
350     QName q;
351
352     if ( colon ) { //qName has prefix
353
354         if ( !uri ) 
355             return SDOM_NAMESPACE_ERR;  
356
357         prefix.nset((char*)qName, (int)colon - (int)qName);
358
359         if ( !strcmp((const char*)prefix,"xml") && strcmp(theXMLNamespace,uri) )
360             //redefinition of xml-namespace
361             return SDOM_NAMESPACE_ERR;
362
363         q.setPrefix(toE(d)->dict().insert((const char*)prefix));
364         q.setLocal(toE(d)->dict().insert((const char*)((int)colon + 1)));
365         q.setUri(toE(d)->dict().insert((const char*)uri));
366
367     } else {
368
369         q.setPrefix(UNDEF_PHRASE);
370         q.setLocal(toE(d)->dict().insert((const char*)qName));
371
372         if ( uri && strcmp((char*)uri,"") ) {
373             q.setUri(toE(d)->dict().insert((const char*)uri));
374         } else {
375             q.setUri(UNDEF_PHRASE);
376         };    
377     };
378
379     *pn = new(&(toTree(d) -> getArena())) Element(*toTree(d), q);
380     // no parent, no childs, no attributes => only 1 namespace:
381     NmSpace* newNS = new(&(toTree(d) -> getArena())) NmSpace(*toTree(d),
382                                                              q.getPrefix(), 
383                                                              q.getUri(), 
384                                                              NSKIND_DECLARED);
385     newNS -> usageCount = 1;
386     toE(*pn) -> namespaces.append(newNS);
387     toV(newNS) -> setParent(toE(*pn));
388     //_TH_ v
389     getTmpList(d).append(*pn);
390     //_TH_ ^
391     return SDOM_OK;
392 }
393 //_JP_ ^
394
395 SDOM_Exception _SDOM_createAttributeWithParent(SablotSituation s, SDOM_Document d, SDOM_Node *pn, const SDOM_char *name, SDOM_Node parent)
396 {
397     QName q;
398     //_JP_ v
399     // uses parent's NSList, if exists
400     if ( parent )
401         toE(parent) -> setLogical(SIT(s), q, name, FALSE);
402     else
403         toRoot(d) -> setLogical(SIT(s), q, name, FALSE);
404     //_JP_ ^ 
405     if ( !isXMLNS_(q, toRoot(d)) ) {
406         *pn = new(&(toTree(d) -> getArena())) 
407             Attribute(*toTree(d), q, (char*)"", XSLA_NONE);
408         if (parent) 
409             toE(parent)->namespaces.incPrefixUsage(q.getPrefix());
410     } else
411         *pn = new(&(toTree(d) -> getArena())) 
412             NmSpace(*toTree(d), 
413                     q.getPrefix() == UNDEF_PHRASE ? UNDEF_PHRASE : q.getLocal(),
414                     UNDEF_PHRASE,
415                     NSKIND_DECLARED);
416     //_TH_ v
417     getTmpList(d).append(*pn);
418     //_TH_ ^
419     return SDOM_OK;
420 }
421
422 SDOM_Exception SDOM_createAttribute(SablotSituation s, SDOM_Document d, SDOM_Node *pn, const SDOM_char *name)
423 {
424     return _SDOM_createAttributeWithParent(s, d, pn, name, NULL);
425 }
426
427 //_JP_ v
428 SDOM_Exception SDOM_createAttributeNS(SablotSituation s, SDOM_Document d, SDOM_Node *pn, const SDOM_char *uri, const SDOM_char *qName)
429 {
430     if ( !isValidQName((char*)qName) )
431         return SDOM_INVALID_CHARACTER_ERR;
432
433     Str prefix = Str();
434     const char *colon = strchr((char*)qName,':');
435     QName q;
436
437     if ( colon ) { //qName has prefix
438
439         if ( !uri )
440             return SDOM_NAMESPACE_ERR;
441
442         prefix.nset((char*)qName, (int)colon - (int)qName);
443
444         if ( !strcmp((const char*)prefix,"xml") && strcmp(theXMLNamespace,uri) )
445             //redefinition of xml namespace
446             return SDOM_NAMESPACE_ERR;
447
448         if ( !strcmp((const char*)prefix,"xmlns") && strcmp(theXMLNSNamespace,uri) )
449             //redefinition of xmlns namespace
450             return SDOM_NAMESPACE_ERR;
451
452         q.setPrefix(toE(d)->dict().insert((const char*)prefix));
453         q.setLocal(toE(d)->dict().insert((const char*)((int)colon + 1)));
454         q.setUri(toE(d)->dict().insert((const char*)uri));
455
456     } else {
457
458         q.setPrefix(UNDEF_PHRASE);
459         q.setLocal(toE(d)->dict().insert((const char*)qName));
460         if ( uri && strcmp((char*)uri,"") ) {
461             q.setUri(toE(d)->dict().insert((const char*)uri));
462         } else {
463             q.setUri(UNDEF_PHRASE);
464         };    
465     };
466
467     if ( !isXMLNS_(q, toRoot(d)) )
468         *pn = new(&(toTree(d) -> getArena())) 
469             Attribute(*toTree(d), q, (char*)"", XSLA_NONE);
470     else
471         *pn = new(&(toTree(d) -> getArena())) 
472             NmSpace(*toTree(d), 
473                     q.getLocal(),
474                     UNDEF_PHRASE,
475                     NSKIND_DECLARED);
476
477     //_TH_ v
478     getTmpList(d).append(*pn);
479     //_TH_ ^
480     return SDOM_OK;
481 }
482 //_JP_ ^
483
484 SDOM_Exception SDOM_createTextNode(SablotSituation s, SDOM_Document d, SDOM_Node *pn, const SDOM_char *data)
485 {
486     *pn = new(&(toTree(d) -> getArena())) Text(*toTree(d), (char*) data);
487     //_TH_ v
488     getTmpList(d).append(*pn);
489     //_TH_ ^
490     return SDOM_OK;
491 }
492
493 SDOM_Exception SDOM_createCDATASection(SablotSituation s, SDOM_Document d, SDOM_Node *pn, const SDOM_char *data)
494 {
495     SE( SDOM_createTextNode(s, d, pn, data) );
496     toText(toV(*pn)) -> beCDATA();
497     return SDOM_OK;
498 }
499
500 SDOM_Exception SDOM_createComment(
501     SablotSituation s, 
502     SDOM_Document d, 
503     SDOM_Node *pn, 
504     const SDOM_char *data)
505 {
506     *pn = new(&(toTree(d) -> getArena())) Comment(*toTree(d), (char*) data);
507     //_TH_ v
508     getTmpList(d).append(*pn);
509     //_TH_ ^
510     return SDOM_OK;
511 }
512
513 SDOM_Exception SDOM_createProcessingInstruction(
514     SablotSituation s, 
515     SDOM_Document d, 
516     SDOM_Node *pn, 
517     const SDOM_char *target,
518     const SDOM_char *data)
519 {
520     *pn = new(&(toTree(d) -> getArena())) ProcInstr(
521         *toTree(d), 
522         toTree(d) -> unexpand((char*) target), 
523         (char*) data);
524     //_TH_ v
525     getTmpList(d).append(*pn);
526     //_TH_ ^
527     return SDOM_OK;
528 }
529
530 SDOM_Exception SDOM_disposeNode(SablotSituation s, SDOM_Node n)
531 {
532     Vertex *v = toV(n);
533     switch(v -> vt & VT_BASE)
534     {
535         case VT_ELEMENT:
536                 ccdelete(v, toE(v)); break;
537             case VT_ATTRIBUTE:
538                 ccdelete(v, toA(v)); break;
539             case VT_NAMESPACE:
540                 ccdelete(v, toNS(v)); break;
541             case VT_PI:
542                 ccdelete(v, toPI(v)); break;
543             case VT_TEXT: // and CDATA
544                 ccdelete(v, toText(v)); break;                          
545             case VT_XSL:
546                 ccdelete(v, toX(v)); break;
547             case VT_COMMENT:
548                 ccdelete(v, toComment(v)); break;
549                 default:
550                     assert(!"disposeSDOM_Node");            
551     }
552     return SDOM_OK;
553 }
554
555 SDOM_Exception SDOM_getNodeType(SablotSituation s, SDOM_Node n, SDOM_NodeType *pType)
556 {
557     Vertex *v = toV(n);
558     switch(basetype(v))
559     {
560         case VT_ROOT:
561                 *pType = SDOM_DOCUMENT_NODE; break;
562         case VT_ELEMENT:
563                 *pType = SDOM_ELEMENT_NODE; break;
564             case VT_ATTRIBUTE:
565                 *pType = SDOM_ATTRIBUTE_NODE; break;
566             case VT_TEXT:
567             {
568                 if (toText(v) -> isCDATA())
569                         *pType = SDOM_CDATA_SECTION_NODE;
570                         else
571                     *pType = SDOM_TEXT_NODE; 
572                 }; break;
573             case VT_COMMENT:
574                 *pType = SDOM_COMMENT_NODE; break;
575                 case VT_PI:
576                     *pType = SDOM_PROCESSING_INSTRUCTION_NODE; break;
577                 case VT_NAMESPACE:
578                   *pType = SDOM_ATTRIBUTE_NODE; break;
579                 default:
580                     *pType = SDOM_OTHER_NODE;
581         }
582         return SDOM_OK;
583 }
584
585 SDOM_Exception SDOM_getNodeName(SablotSituation s, SDOM_Node n, SDOM_char **pName)
586 {
587     Str fullName;
588     Vertex *v = toV(n);
589     switch(v -> vt & VT_BASE)
590     {
591     case VT_ELEMENT:
592     {
593         v -> getOwner().expandQStr(toE(v) -> getName(), fullName);
594         *pName = SDOM_newString(fullName);
595     };
596     break;
597     case VT_ATTRIBUTE:
598     {
599         v -> getOwner().expandQStr(toA(v) -> getName(), fullName);
600         *pName = SDOM_newString(fullName);
601     };
602     break;
603     case VT_NAMESPACE:
604     {
605         v -> getOwner().expandQStr(toNS(v) -> getName(), fullName);
606         DStr fullName2 = "xmlns";
607         if ( strcmp(fullName,"") ) {
608           fullName2 += ":";
609           fullName2 += fullName;
610         }
611         *pName = SDOM_newString(fullName2);
612     };
613     break;
614     case VT_TEXT: // and CDATA
615     {
616         if (toText(v) -> isCDATA())
617             *pName = SDOM_newString("#cdata-section");
618         else
619             *pName = SDOM_newString("#text"); 
620     }; break;           
621     case VT_COMMENT:
622         *pName = SDOM_newString("#comment"); break;
623     case VT_ROOT:
624         *pName = SDOM_newString("#document"); break;                
625     case VT_PI:
626         *pName = SDOM_newString(toPI(v) -> getOwner().expand(toPI(v) -> getName().getLocal())); break;          
627             
628     default:
629         *pName = NULL;
630     }
631     return SDOM_OK;
632 }
633
634 SDOM_Exception SDOM_getNodeNSUri(SablotSituation s, SDOM_Node n, SDOM_char **pName)
635 {
636     Str value;
637     Vertex *v = toV(n);
638     switch(v -> vt & VT_BASE)
639     {
640     case VT_ELEMENT:
641     {
642         value = v -> getOwner().expand(toE(v) -> getName().getUri());
643         *pName = SDOM_newString(value);
644     };
645     break;
646     case VT_ATTRIBUTE:
647     {
648         value = v -> getOwner().expand(toA(v) -> getName().getUri());
649         *pName = SDOM_newString(value);
650     };
651     break;
652     case VT_NAMESPACE:
653     {
654       *pName = SDOM_newString(theXMLNSNamespace);
655     };
656     break;
657     default:
658         *pName = NULL;
659     }
660     return SDOM_OK;
661 }
662
663 SDOM_Exception SDOM_getNodePrefix(SablotSituation s, SDOM_Node n, SDOM_char **pName)
664 {
665     Str value;
666     Vertex *v = toV(n);
667     switch(v -> vt & VT_BASE)
668     {
669     case VT_ELEMENT:
670     {
671         value = v -> getOwner().expand(toE(v) -> getName().getPrefix());
672         *pName = SDOM_newString(value);
673     };
674     break;
675     case VT_ATTRIBUTE:
676     {
677         value = v -> getOwner().expand(toA(v) -> getName().getPrefix());
678         *pName = SDOM_newString(value);
679     };
680     break;
681     case VT_NAMESPACE:
682     {
683         v -> getOwner().expandQStr(toNS(v) -> getName(), value);
684         if ( !strcmp(value,"") ) {
685           *pName = SDOM_newString("");
686         } else {
687           *pName = SDOM_newString("xmlns");
688         };
689     };
690     break;
691     default:
692         *pName = NULL;
693     }
694     return SDOM_OK;
695 }
696
697 SDOM_Exception SDOM_getNodeLocalName(SablotSituation s, SDOM_Node n, SDOM_char **pName)
698 {
699     Str value;
700     Vertex *v = toV(n);
701     switch(v -> vt & VT_BASE)
702     {
703     case VT_ELEMENT:
704     {
705         value = v -> getOwner().expand(toE(v) -> getName().getLocal());
706         *pName = SDOM_newString(value);
707     };
708     break;
709     case VT_ATTRIBUTE:
710     {
711         value = v -> getOwner().expand(toA(v) -> getName().getLocal());
712         *pName = SDOM_newString(value);
713     };
714     break;
715     case VT_NAMESPACE:
716     {
717         v -> getOwner().expandQStr(toNS(v) -> getName(), value);
718         if ( !strcmp(value,"") ) {
719           *pName = SDOM_newString("xmlns");
720         } else {
721           value = v -> getOwner().expand(toNS(v) -> getName().getLocal());
722           *pName = SDOM_newString(value);
723         };
724
725         
726     };
727     break;
728     default:
729         *pName = NULL;
730     }
731     return SDOM_OK;
732 }
733
734 SDOM_Exception SDOM_setNodeName(SablotSituation s, SDOM_Node n, const SDOM_char *name)
735 {
736     Vertex *v = toV(n);
737     QName q;
738     if (isRoot(v))
739         SDOM_Err(s, SDOM_NO_MODIFICATION_ALLOWED_ERR);
740     switch (v -> vt & VT_BASE) 
741     {
742     case VT_ELEMENT:
743         toE(v) -> setLogical(SIT(s), q, name, TRUE);
744         break;
745     default:
746     {
747         if (v -> parent)
748             toE(v -> parent) -> setLogical(SIT(s), q, name, FALSE);
749         else
750             v -> getOwner().getRoot().setLogical(SIT(s), q, name, FALSE);
751     }
752     }
753
754     switch(v -> vt & VT_BASE)
755     {
756     case VT_ELEMENT:
757         if ( q.getPrefix() != UNDEF_PHRASE && !toE(v) -> namespaces.find(q.getPrefix()) )
758           SDOM_Err(s, SDOM_NAMESPACE_ERR);
759         toE(v) -> namespaces.decPrefixUsage(toE(v) -> name.getPrefix());
760         toE(v) -> name = q;
761         toE(v) -> namespaces.incPrefixUsage(q.getPrefix());
762         break;
763     case VT_ATTRIBUTE:
764           if ( toA(v) -> parent ) {
765             Phrase curPrefix = toA(v) -> name.getPrefix(); 
766             Phrase newPrefix = q.getPrefix(); 
767             if ( (newPrefix != UNDEF_PHRASE 
768                   && !toE(toA(v) -> parent) -> namespaces.find(newPrefix))
769                  || 
770                  (newPrefix == toA(v)-> getOwner().stdPhrase(PHRASE_XMLNS) 
771                   || !strcmp(name,"xmlns")) ){
772               //attempt to change attribute to namespace
773               SDOM_Err(s, SDOM_NAMESPACE_ERR);
774             };
775             if ( curPrefix != UNDEF_PHRASE)
776               toE(toA(v) -> parent) -> namespaces.decPrefixUsage(curPrefix);
777             toA(v) -> name = q;
778             if ( newPrefix != UNDEF_PHRASE)
779               toE(toA(v) -> parent) -> namespaces.incPrefixUsage(newPrefix);
780           } else 
781             toA(v) -> name = q;
782           break;
783     case VT_NAMESPACE:
784     {
785       if ( strcmp(name,"xmlns") ) {
786         if ( !(q.getPrefix() == toNS(v)-> getOwner().stdPhrase(PHRASE_XMLNS)) ) {
787           //attempt to change namespace to attribute
788           SDOM_Err(s, SDOM_NAMESPACE_ERR);
789         };
790       } else {
791         //default namespace
792         q.setLocal(UNDEF_PHRASE);
793       };
794       q.setPrefix(UNDEF_PHRASE);
795       if ( !(toNS(v) -> name == q) ) {
796         if ( toNS(v) -> usageCount != 0 ) {
797           SDOM_Err(s, SDOM_NO_MODIFICATION_ALLOWED_ERR);
798         } else {
799           toNS(v) -> prefix = q.getLocal();
800           toNS(v) -> name = q;
801         };
802       };
803     }; break;
804     case VT_PI:
805         toPI(v) -> name = q;
806         break;
807     default:
808         SDOM_Err(s, SDOM_NO_MODIFICATION_ALLOWED_ERR);
809     }
810     return SDOM_OK;
811 }
812
813 SDOM_Exception SDOM_getNodeValue(SablotSituation s, SDOM_Node n, SDOM_char **pValue)
814 {
815     Vertex *v = toV(n);
816     switch(v -> vt & VT_BASE)
817     {
818             case VT_ATTRIBUTE:
819                 *pValue = SDOM_newString(toA(v) -> cont);
820                     break;
821             case VT_NAMESPACE:
822                 *pValue = SDOM_newString(v -> getOwner().expand(toNS(v) -> uri));
823                     break;
824             case VT_TEXT: // and CDATA section
825                 *pValue = SDOM_newString(toText(v) -> cont);
826                     break;
827             case VT_COMMENT:
828                 *pValue = SDOM_newString(toComment(v) -> cont);
829                     break;
830                 case VT_PI:
831                 *pValue = SDOM_newString(toPI(v) -> cont);
832                     break;
833                 default:
834                     // element and document (root) have void value
835                     *pValue = NULL;
836         }
837         return SDOM_OK;
838 }
839
840 SDOM_Exception SDOM_setNodeValue(SablotSituation s, SDOM_Node n, const SDOM_char *value)
841 {
842     Vertex *v = toV(n);
843     switch(v -> vt & VT_BASE)
844     {
845             case VT_ATTRIBUTE:
846                 toA(v) -> cont = value;
847                     break;
848             case VT_NAMESPACE:
849                 SE( __SDOM_canChangeUriNS(s, toNS(v) -> parent, toNS(v), value) );
850                 toNS(v) -> uri = v -> getOwner().unexpand(value);
851                     break;
852             case VT_TEXT: // and CDATA section
853                 toText(v) -> cont = value;
854                     break;
855             case VT_COMMENT:
856                 toComment(v) -> cont = value;
857                     break;
858                 case VT_PI:
859                 toPI(v) -> cont = value;
860                     break;
861                 default:
862                     // element and document (root) have void value
863                     SDOM_Err(s, SDOM_NO_MODIFICATION_ALLOWED_ERR);
864         }
865         return SDOM_OK;
866 }
867
868 SDOM_Exception SDOM_getParentNode(SablotSituation s, SDOM_Node n, SDOM_Node *pParent)
869 {
870     Vertex *v = toV(n);
871     if (isRoot(v) || isAttr(v) || isNS(v))
872         *pParent = NULL;
873         else
874             *pParent = v -> parent;
875         return SDOM_OK;
876 }
877
878 SDOM_Exception SDOM_getFirstChild(SablotSituation s, SDOM_Node n, SDOM_Node *pFirstChild)
879 {
880     Vertex *v = toV(n);
881     if (!isElement(v) && !isRoot(v))
882         *pFirstChild = NULL;
883         else
884         {
885             int childCount = toE(v) -> contents.number();
886             if (childCount)
887                 *pFirstChild = (SDOM_Node)(toE(v) -> contents[0]);
888                 else
889                     *pFirstChild = NULL;
890         }
891         return SDOM_OK;
892 }
893
894 SDOM_Exception SDOM_getLastChild(SablotSituation s, SDOM_Node n, SDOM_Node *pLastChild)
895 {
896     Vertex *v = toV(n);
897     if (!isElement(v) && !isRoot(v))
898         *pLastChild = NULL;
899         else
900         {
901             int childCount = toE(v) -> contents.number();
902             if (childCount)
903                 *pLastChild = (SDOM_Node)(toE(v) -> contents.last());
904                 else
905                     *pLastChild = NULL;
906         }
907         return SDOM_OK;
908 }
909
910 SDOM_Exception SDOM_getPreviousSibling(SablotSituation s, SDOM_Node n, SDOM_Node *pPreviousSibling)
911 {
912     switch(toV(n) -> vt & VT_BASE)
913     {
914         case VT_ATTRIBUTE:
915             case VT_NAMESPACE:
916         case VT_ROOT:               
917                 *pPreviousSibling = NULL;
918                     break;
919         default:
920             *pPreviousSibling = toV(n) -> getPreviousSibling();
921         }
922     return SDOM_OK;
923 }
924
925 SDOM_Exception SDOM_getNextSibling(SablotSituation s, SDOM_Node n, SDOM_Node *pNextSibling)
926 {
927     switch(toV(n) -> vt & VT_BASE)
928     {
929         case VT_ATTRIBUTE:
930         case VT_NAMESPACE:    
931         case VT_ROOT:               
932                 *pNextSibling = NULL;
933                     break;
934         default:
935             *pNextSibling = toV(n) -> getNextSibling();
936         }
937     return SDOM_OK;
938 }
939
940 SDOM_Exception SDOM_getChildNodeIndex(SablotSituation s, SDOM_Node n, int index, SDOM_Node *pChildNode)
941 {
942     Vertex *v = toV(n);
943     if ( (!isElement(v) && !isRoot(v))
944          || index < 0 
945          || index >= toE(v) -> contents.number() )
946         *pChildNode = NULL;  
947     else
948         *pChildNode = (SDOM_Node)(toE(n) -> contents[index]);
949     return SDOM_OK;
950 }
951
952 SDOM_Exception SDOM_getChildNodeCount(SablotSituation s, SDOM_Node n, int *count)
953 {
954     Vertex *v = toV(n);
955     if ( !isElement(v) && !isRoot(v) )
956         *count = 0;  
957     else
958         *count = toE(v) -> contents.number();
959     return SDOM_OK;
960 }
961
962 SDOM_Exception SDOM_getOwnerDocument(SablotSituation s, SDOM_Node n, SDOM_Document *pOwnerDocument)
963 {
964     if (isRoot(toV(n)))
965         *pOwnerDocument = NULL;
966         else
967         *pOwnerDocument = ownerDoc(n);
968     return SDOM_OK;
969 }
970
971 Bool hasElementChild(RootNode *r)
972 {
973     for (int i = 0; i < r -> contents.number(); i++)
974         if (isElement(r -> contents[i]))
975           return TRUE;
976     return FALSE;
977 }
978
979 // is first ancestor of second?
980 Bool isAncestor(Vertex *first, Vertex *second)
981 {
982     for (Vertex *p = second; p; p = p -> parent)
983         if (p == first) return TRUE;
984         return FALSE;
985 }
986
987 SDOM_Exception SDOM_insertBefore(SablotSituation s, SDOM_Node n, SDOM_Node newChild, SDOM_Node refChild)
988 {
989     Vertex *v = toV(n);
990     
991     // check if v is an element (or root)
992     if (!isElement(v))
993         SDOM_Err(s, SDOM_HIERARCHY_REQUEST_ERR);
994         
995         // check the type of newChild
996         if (!newChild)
997             SDOM_Err(s, SDOM_NOT_FOUND_ERR)
998         else
999             switch(basetype(newChild))
1000         {
1001             case VT_ATTRIBUTE:
1002             case VT_NAMESPACE:
1003             case VT_ROOT:
1004                 SDOM_Err(s, SDOM_HIERARCHY_REQUEST_ERR);            
1005         }    
1006         // check if newChild is from the same doc
1007         if ((isRoot(v) && ownerDoc(newChild) != v) ||
1008             (!isRoot(v) && ownerDoc(v) != ownerDoc(newChild)))
1009             SDOM_Err(s, SDOM_WRONG_DOCUMENT_ERR);
1010         
1011         // check type of the reference child
1012         if (refChild)
1013             switch(toV(refChild) -> vt & VT_BASE)
1014         {
1015             case VT_ATTRIBUTE:
1016             case VT_NAMESPACE:
1017             case VT_ROOT:
1018                 SDOM_Err(s, SDOM_HIERARCHY_REQUEST_ERR);            
1019         }
1020         
1021         // check if newChild is not an ancestor of n
1022         if (isAncestor(toV(newChild), toV(n)))
1023             SDOM_Err(s, SDOM_HIERARCHY_REQUEST_ERR);
1024             
1025         // check if not attempting to have more doc elements
1026         if (isRoot(v) && isElement(newChild) && hasElementChild(toRoot(v)))
1027             SDOM_Err(s, SDOM_HIERARCHY_REQUEST_ERR);
1028             
1029         // see if newChild needs to be removed from tree
1030         Vertex *parent;
1031         if (NULL != (parent = toV(newChild) -> parent))
1032             SE( SDOM_removeChild(s, parent, newChild) );
1033         //_JP_ v
1034 //      // v ??? 
1035 //      int ndx = toE(v) -> contents.getIndex(toV(newChild));
1036 //      if (ndx != -1)
1037 //          toE(v) -> contents.rm(ndx);
1038 //      // ^ ???
1039 //      //_TH_ v
1040 //      getTmpList(n).rmP(newChild);
1041 //      //_TH_ ^
1042         int ndx = toE(v) -> contents.getIndex(toV(newChild));
1043         if (ndx != -1)
1044             toE(v) -> contents.rm(ndx);
1045         else
1046             getTmpList(n).rmP(newChild);
1047         //_JP_ ^
1048         if (refChild)
1049         {
1050         ndx = toE(v) -> contents.getIndex(toV(refChild));
1051             if (ndx == -1)
1052                 SDOM_Err(s, SDOM_NOT_FOUND_ERR);
1053             toE(v) -> contents.insertBefore(toV(newChild), ndx);
1054         }
1055         else
1056             toE(v) -> contents.append(toV(newChild));
1057             // toE(v) -> contents.appendAndSetOrdinal(toV(newChild));
1058         toV(newChild) -> setParent(v);
1059         //_JP_ v
1060         //old_parent's not used namespaces was cleaned by SDOM_removeChild
1061         SE( __SDOM_swallowParentNS(s, newChild) );
1062         //_JP_ ^
1063         return SDOM_OK;
1064 }
1065
1066 SDOM_Exception SDOM_removeChild(SablotSituation s, SDOM_Node n, SDOM_Node oldChild)
1067 {
1068     Vertex *v = toV(n);
1069     if (!isElement(v))
1070         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1071         switch(toV(oldChild) -> vt & VT_BASE)
1072         {
1073             case VT_ATTRIBUTE:
1074             case VT_NAMESPACE:
1075             case VT_ROOT:
1076                 SDOM_Err(s, SDOM_INVALID_NODE_TYPE);        
1077         }
1078         if (toV(oldChild) -> parent != toV(n))
1079             SDOM_Err(s, SDOM_NOT_FOUND_ERR);
1080         //_JP_ v
1081         SE( __SDOM_dropParentNS(s, oldChild) );
1082         //_JP_ ^
1083         toE(v) -> removeChild(toV(oldChild));
1084         //_TH_ v
1085         getTmpList(n).append(oldChild);
1086         //_TH_ ^
1087     return SDOM_OK;
1088 }
1089
1090 SDOM_Exception SDOM_replaceChild(SablotSituation s, SDOM_Node n, SDOM_Node newChild, SDOM_Node oldChild)
1091 {
1092     SDOM_Node tmp;
1093     SE( SDOM_getParentNode(s, newChild, &tmp) );
1094     if (tmp) SE( SDOM_removeChild(s, tmp, newChild) );
1095     
1096     SE( SDOM_getNextSibling(s, oldChild, &tmp) );
1097     SE( SDOM_removeChild(s, n, oldChild) );
1098     SE( SDOM_insertBefore(s, n, newChild, tmp) );
1099     
1100     //_JP_ old version not satisfying DOM spec:
1101     //SE( SDOM_insertBefore(s, n, newChild, oldChild) );
1102     //SE( SDOM_removeChild(s, n, oldChild) );
1103
1104     return SDOM_OK;
1105 }
1106
1107 SDOM_Exception SDOM_appendChild(SablotSituation s, SDOM_Node n, SDOM_Node newChild)
1108 {
1109     return SDOM_insertBefore(s, n, newChild, NULL);
1110 }
1111
1112 SDOM_Exception cloneVertex(SablotSituation, Tree *, Vertex *, int, Vertex **);
1113
1114 SDOM_Exception cloneVertexList(SablotSituation s, Tree *t, VertexList *vlForeign, int deep, Element *tParent)
1115 {
1116     Vertex *newVertex;
1117     for (int i = 0; i < vlForeign -> number(); i++)
1118     {
1119         SE( cloneVertex(s, t, (*vlForeign)[i], deep, &newVertex) );
1120             // the following also handles atts and namespaces correctly
1121             tParent -> newChild(SIT(s), newVertex);         
1122     }   
1123     return SDOM_OK;
1124 }
1125
1126 SDOM_Exception cloneVertex(SablotSituation s, Tree *t, Vertex *foreign, int deep, Vertex **clone)
1127 {
1128     Tree *tForeign = &(foreign -> getOwner());
1129     QName q;
1130     EQName expanded;
1131
1132         if (basetype(foreign) == VT_ROOT) 
1133             SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1134
1135         // get the correctly unexpanded name    
1136         if (basetype(foreign) == VT_ELEMENT || 
1137             basetype(foreign) == VT_ATTRIBUTE ||
1138             basetype(foreign) == VT_PI ||
1139             basetype(foreign) == VT_NAMESPACE)
1140         {       
1141         switch(basetype(foreign))
1142         {
1143             case VT_ELEMENT:
1144                     tForeign -> expandQ(toE(foreign) -> getName(), expanded);
1145                     break;
1146             case VT_ATTRIBUTE:
1147                     tForeign -> expandQ(toA(foreign) -> getName(), expanded);
1148                     break;
1149             case VT_NAMESPACE:
1150                     tForeign -> expandQ(toNS(foreign) -> getName(), expanded);
1151                     break;
1152                 case VT_PI:
1153                     tForeign -> expandQ(toPI(foreign) -> getName(), expanded);
1154                     break;
1155         };
1156             q.setLocal(t -> unexpand(expanded.getLocal()));
1157             q.setPrefix(t -> unexpand(expanded.getPrefix()));
1158             q.setUri(t -> unexpand(expanded.getUri()));
1159     }
1160
1161     // create the actual copy
1162     switch(basetype(foreign))
1163     {
1164         case VT_ELEMENT:
1165             *clone = new(&(t -> getArena())) 
1166                     Element(*t, q);
1167                 break;
1168             case VT_ATTRIBUTE:
1169             *clone = new(&(t -> getArena())) 
1170                     Attribute(*t, q, toA(foreign) -> cont, XSLA_NONE);
1171                     break;
1172                 case VT_NAMESPACE:
1173             *clone = new(&(t -> getArena())) NmSpace(*t, 
1174                     t -> unexpand(tForeign -> expand(toNS(foreign) -> prefix)),
1175                         t -> unexpand(tForeign -> expand(toNS(foreign) -> uri)),
1176                         toNS(foreign) -> kind);
1177             // _JP_ v
1178             toNS(*clone) -> usageCount = toNS(foreign) -> usageCount;
1179             // _JP_ ^
1180                     break;
1181                 case VT_PI:
1182             *clone = new(&(t -> getArena())) ProcInstr(*t, q.getLocal(), toPI(foreign) -> cont);
1183                     break;
1184             case VT_COMMENT:
1185             *clone = new(&(t -> getArena())) Comment(*t, toComment(foreign) -> cont);
1186                     break;
1187             case VT_TEXT:
1188                 {
1189                     *clone = new(&(t -> getArena())) Text(*t, toText(foreign) -> cont);                         
1190                 if (toText(foreign) -> isCDATA())               
1191                     toText(*clone) -> beCDATA();
1192                         }; break;
1193     }
1194     
1195     if (isElement(foreign))
1196     {
1197         // must clone atts and namespaces in any case
1198             assert(isElement(*clone));
1199         cloneVertexList(s, t, &(toE(foreign) -> atts), deep, toE(*clone));
1200         cloneVertexList(s, t, &(toE(foreign) -> namespaces), deep, toE(*clone));
1201             
1202             // if deep then recurse
1203             if (deep)
1204             cloneVertexList(s, t, &(toE(foreign) -> contents), deep, toE(*clone));        
1205         }
1206     return SDOM_OK;
1207 }
1208
1209 SDOM_Exception SDOM_cloneForeignNode(SablotSituation s, SDOM_Document d, SDOM_Node n, int deep, SDOM_Node *clone)
1210 {
1211   SDOM_Exception se = cloneVertex(s, toTree(d), toV(n), deep, (Vertex**) clone);
1212     //_JP_ v
1213   se = (se != SDOM_OK) ? se : __SDOM_dropParentNS(s, *clone);
1214     //_JP_ ^
1215     //_TH_ v
1216   getTmpList(d).append(*clone);
1217     //_TH_ ^
1218   return se;
1219 }
1220
1221 SDOM_Exception SDOM_cloneNode(SablotSituation s, SDOM_Node n, int deep, SDOM_Node *clone)
1222 {
1223     return SDOM_cloneForeignNode(s, ownerDoc(n), n, deep, clone);
1224 }
1225
1226 SDOM_Exception SDOM_getAttribute(SablotSituation s, SDOM_Node n, const SDOM_char *name, SDOM_char **pValue)
1227 {
1228     QName q;
1229     if (!isElement(toV(n)))
1230         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1231     Element *e = toE(toV(n));
1232
1233     e -> setLogical(SIT(s), q, name, FALSE);
1234     Vertex *v = NULL;
1235     Bool isXMLNS = isXMLNS_(q, e);
1236     if (!isXMLNS)
1237         v = e -> atts.find(q);
1238         else
1239             v = e -> namespaces.find(
1240                 q.getLocal() != UNDEF_PHRASE ? q.getLocal() : UNDEF_PHRASE);
1241     if (!v)
1242         *pValue = SDOM_newString("");
1243         else
1244         {
1245             if (!isXMLNS)
1246               *pValue = SDOM_newString(toA(v) -> cont);
1247             else
1248               *pValue = SDOM_newString(e -> getOwner().expand(toNS(v) -> uri));
1249         }
1250     return SDOM_OK;         
1251 }
1252
1253 SDOM_Exception SDOM_getAttributeNS(SablotSituation s, SDOM_Node n, SDOM_char *uri, SDOM_char *local, SDOM_char **pValue)
1254 {
1255     QName q;
1256     if (!isElement(toV(n)))
1257         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1258     Element *e = toE(toV(n));
1259
1260     Vertex *v = NULL;
1261     Bool isXMLNS = ( !strcmp((char*)uri,theXMLNSNamespace) );
1262     if ( !isXMLNS ) {
1263         const int attcount = e -> atts.number();
1264         for (int i = 0; i < attcount; i++) {
1265           q = toA(e->atts[i]) -> name;
1266           if (!strcmp((char*)local, (char*)(e -> getOwner().expand(q.getLocal())))
1267               && !strcmp((char*)uri, (char*)(e -> getOwner().expand(q.getUri())))) {
1268             v = e -> atts[i];
1269             break;
1270           };
1271         };
1272     } else {
1273         const int nscount = e -> namespaces.number();
1274         for (int i = 0; i < nscount; i++) {
1275           q = toNS(e->namespaces[i]) -> name;
1276           if (!strcmp((char*)local, (char*)(e -> getOwner().expand(toNS(e->namespaces[i])->prefix)))) {
1277             v = e -> namespaces[i];
1278             break;
1279           };
1280         };
1281     }
1282     if (!v)
1283         *pValue = SDOM_newString("");
1284         else
1285         {
1286             if (!isXMLNS)
1287               *pValue = SDOM_newString(toA(v) -> cont);
1288             else
1289               *pValue = SDOM_newString(e -> getOwner().expand(toNS(v) -> uri));
1290         }
1291     return SDOM_OK;         
1292 }
1293
1294 SDOM_Exception SDOM_getAttributeNode(SablotSituation s, SDOM_Node n, const SDOM_char *name, SDOM_Node *attr)
1295 {
1296     QName q;
1297     if ( !isElement(toV(n)) )
1298         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1299     Element *e = toE(toV(n));
1300
1301     e -> setLogical(SIT(s), q, name, FALSE);
1302     Vertex *v = NULL;
1303     Bool isXMLNS = isXMLNS_(q, e);
1304     if (!isXMLNS)
1305         v = e -> atts.find(q);
1306         else
1307           {
1308             v = e -> namespaces.find(
1309                         q.getLocal() != e -> getOwner().stdPhrase(PHRASE_XMLNS)? 
1310                                      q.getLocal() : UNDEF_PHRASE);
1311           }
1312     if (!v)
1313         *attr = 0;
1314     else
1315       {
1316         *attr = (SDOM_Node)v;
1317       }
1318     return SDOM_OK;         
1319 }
1320
1321 SDOM_Exception SDOM_getAttributeNodeNS(SablotSituation s, SDOM_Node n, SDOM_char *uri, SDOM_char *local, SDOM_Node *attr)
1322 {
1323     QName q;
1324     if (!isElement(toV(n)))
1325         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1326     Element *e = toE(toV(n));
1327
1328     Vertex *v = NULL;
1329     if ( strcmp((char*)uri,theXMLNSNamespace) ) {
1330       //true attribute
1331         const int attcount = e -> atts.number();
1332         for (int i = 0; i < attcount; i++) {
1333           q = toA(e->atts[i]) -> name;
1334           if (!strcmp((char*)local, (char*)(e -> getOwner().expand(q.getLocal())))
1335               && !strcmp((char*)uri, (char*)(e -> getOwner().expand(q.getUri())))) {
1336             v = e -> atts[i];
1337             break;
1338           };
1339         };
1340     } else {
1341       //namespace
1342         const int nscount = e -> namespaces.number();
1343         char* pre;
1344         if ( !strcmp(local,"xmlns") )
1345           pre = "";
1346         else
1347           pre = (char*)local;
1348         
1349         for (int i = 0; i < nscount; i++) {
1350           q = toNS(e->namespaces[i]) -> name;
1351           if (!strcmp(pre, (char*)(e -> getOwner().expand(toNS(e->namespaces[i])->prefix)))) {
1352             v = e -> namespaces[i];
1353             break;
1354           };
1355         };
1356     };
1357     *attr = v;
1358     return SDOM_OK;
1359 }
1360
1361 SDOM_Exception SDOM_getAttributeNodeIndex(SablotSituation s, SDOM_Node n, const int index, SDOM_Node *attr)
1362 {
1363     if (!isElement(toV(n)))
1364         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1365     Element *e = toE(toV(n));
1366     int nscount = e -> namespaces.number();
1367
1368     if (index < 0 || index >= nscount + e -> atts.number() )
1369         *attr = NULL;
1370     else
1371         if (index < nscount)
1372             *attr = (SDOM_Node)(e -> namespaces[index]);
1373         else 
1374             *attr = (SDOM_Node)(e -> atts[index-nscount]);
1375     return SDOM_OK;         
1376 }
1377
1378 SDOM_Exception SDOM_getAttributeNodeCount(SablotSituation s, SDOM_Node n, int *count)
1379 {
1380     if (!isElement(toV(n)))
1381         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1382     Element *e = toE(toV(n));
1383     *count = e -> namespaces.number()  +  e -> atts.number();
1384     return SDOM_OK;         
1385 }
1386
1387
1388 SDOM_Exception SDOM_setAttribute(SablotSituation s, SDOM_Node n, const SDOM_char *attName, const SDOM_char *attValue)
1389 {
1390     QName q;
1391     if (!isElement(toV(n)))
1392         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1393     Element *e = toE(toV(n));
1394
1395     e -> setLogical(SIT(s), q, attName, FALSE);
1396     Vertex *v;
1397     if ( !isXMLNS_(q, e) ) {
1398         v = e -> atts.find(q);
1399         if (!v) {
1400             SE( _SDOM_createAttributeWithParent(s, ownerDoc(e), (SDOM_Node*) &v, attName, e));
1401             //_TH_ v
1402             getTmpList(n).rmP(v);
1403             //_TH_ ^
1404             e -> atts.append(toA(v));
1405             toV(v) -> setParent(e);
1406         };
1407         SE( SDOM_setNodeValue(s, v, attValue) );        
1408     } else { //attribute is namespace declaration
1409         v = e -> namespaces.find(q.getLocal() != e -> getOwner().stdPhrase(PHRASE_XMLNS) ? q.getLocal() : UNDEF_PHRASE);
1410         if (!v) {
1411             SE( _SDOM_createAttributeWithParent(s, ownerDoc(e), (SDOM_Node*) &v, attName, e));
1412             //_TH_ v
1413             getTmpList(n).rmP(v);
1414             //_TH_ ^
1415             e -> namespaces.append(toNS(v));
1416             toV(v) -> setParent(e);
1417         };
1418         SE( SDOM_setNodeValue(s, v, attValue) );
1419         //_JP_ v
1420         toNS(v) -> kind = NSKIND_DECLARED;      
1421         SE( __SDOM_refreshNS(s, n, toNS(v)) );
1422         //_JP_ ^        
1423     };
1424
1425     return SDOM_OK;         
1426 }
1427
1428 //_JP_ v
1429 SDOM_Exception SDOM_setAttributeNS(SablotSituation s, SDOM_Node n, const SDOM_char *uri, const SDOM_char *qName, const SDOM_char *value)
1430 {
1431     if (!isElement(toV(n)))
1432         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1433
1434     if ( !isValidQName((char*)qName) )
1435         SDOM_Err(s, SDOM_INVALID_CHARACTER_ERR);
1436
1437     QName q;
1438     Element *e = toE(toV(n));
1439     Str prefix = Str();
1440     char *colon = strchr((char*)qName,':');
1441
1442     if ( colon ) { //qName has prefix
1443
1444         if ( !uri ) 
1445             SDOM_Err(s, SDOM_NAMESPACE_ERR);  
1446
1447         prefix.nset((char*)qName, (int)colon - (int)qName);
1448
1449         if ( !strcmp((const char*)prefix,"xml") && strcmp(theXMLNamespace,uri) )
1450             //redefinition of xml-namespace
1451             SDOM_Err(s, SDOM_NAMESPACE_ERR);
1452
1453         if ( !strcmp((const char*)prefix,"xmlns") && strcmp(theXMLNSNamespace,uri) )
1454             //redefinition of xmlns-namespace
1455             SDOM_Err(s, SDOM_NAMESPACE_ERR);
1456
1457         q.setPrefix(ownerDoc(toE(n))->dict().insert((const char*)prefix));
1458         q.setLocal(ownerDoc(toE(n))->dict().insert((const char*)((int)colon + 1)));
1459         q.setUri(ownerDoc(toE(n))->dict().insert((const char*)uri));
1460
1461     } else {
1462
1463         q.setPrefix(UNDEF_PHRASE);
1464         q.setLocal(ownerDoc(toE(n))->dict().insert((const char*)qName));
1465
1466         if ( uri && strcmp((char*)uri,"") ) {
1467             q.setUri(ownerDoc(toE(n))->dict().insert((const char*)uri));
1468         } else {
1469             q.setUri(UNDEF_PHRASE);
1470         };    
1471     };
1472
1473     SDOM_Node replaced;
1474     SE( SDOM_getAttributeNodeNS(s, n, 
1475                                 (SDOM_char*)(e -> getOwner().expand(q.getUri())), 
1476                                 (SDOM_char*)(e -> getOwner().expand(q.getLocal())),
1477                                 &replaced) );
1478
1479     if ( strcmp((char*)uri, theXMLNSNamespace) ) {
1480       //true attribute
1481       if ( replaced ) {
1482         //attr with the same uri:local found
1483         if ( q.getPrefix() == toA(replaced)->name.getPrefix() ) {
1484           //the same prefix
1485         } else {
1486           //prefix != replaced.prefix
1487           if ( q.getPrefix() != UNDEF_PHRASE ) {
1488             SE( __SDOM_touchNS(s, n, 
1489                                q.getPrefix(), 
1490                                q.getUri(),
1491                                NSKIND_PARENT, 0) );
1492             e -> namespaces.decPrefixUsage(toA(replaced)->name.getPrefix());
1493           };
1494           toA(replaced)->name.setPrefix(q.getPrefix());
1495         };
1496       } else {
1497         //attr with the same uri:local NOT found
1498         if ( q.getPrefix() != UNDEF_PHRASE )
1499           SE( __SDOM_touchNS(s, n, 
1500                              q.getPrefix(), 
1501                              q.getUri(),
1502                              NSKIND_PARENT, 0) );
1503         replaced = new(&(toTree(ownerDoc(e)) -> getArena())) 
1504                    Attribute(*toTree(ownerDoc(e)), q, (char*)"", XSLA_NONE);
1505         e -> atts.append(toA(replaced));
1506         toV(replaced) -> setParent(e);
1507       };
1508       SE( SDOM_setNodeValue(s, replaced, value) );
1509       
1510     } else {
1511       // att is namespace
1512       SE( __SDOM_touchNSByChar(s, n, 
1513                                (SDOM_char*)(e -> getOwner().expand(q.getLocal())), 
1514                                (SDOM_char*)value,
1515                                NSKIND_DECLARED, 0) );
1516   };
1517     return SDOM_OK;         
1518 }
1519
1520
1521 SDOM_Exception SDOM_setAttributeNode(SablotSituation s, SDOM_Node n, SDOM_Node attnode, SDOM_Node *replaced)
1522 {
1523   if ( !( isElement(toV(n)) && (isAttr(toV(attnode)) 
1524                                 || isNS(toV(attnode))) ) )
1525     SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1526   if ( ownerDoc(n) != ownerDoc(attnode) )
1527     SDOM_Err(s, SDOM_WRONG_DOCUMENT_ERR);
1528   if ( toV(attnode) -> parent )
1529     SDOM_Err(s, SDOM_INUSE_ATTRIBUTE_ERR);
1530   Element *e = toE(toV(n));
1531   //NmSpace *nm;
1532   if ( isAttr(toV(attnode)) ) {
1533     Str attname;
1534     e -> getOwner().expandQStr(toA(attnode) -> getName(), attname);
1535     SE( SDOM_getAttributeNode(s, n, (SDOM_char*)attname, replaced) );
1536     if ( *replaced ) {
1537       //attr with the same prefix:local found
1538       if ( toA(attnode)->name.getUri() == toA(*replaced)->name.getUri() ) {
1539         //the same uri
1540 //      int ndx = e -> atts.findNdx(toA(*replaced)->name);
1541 //      toV(*replaced) -> parent = NULL;
1542 //      //_TH_ v
1543 //      getTmpList(n).append(*replaced);
1544 //      //_TH_ ^
1545 //      e -> atts[ndx] = toV(attnode);
1546         //_JP_ v
1547         int ndx = toV(*replaced) -> ordinal;
1548         toV(*replaced) -> parent = NULL;
1549         //_TH_ v
1550         getTmpList(n).append(*replaced);
1551         getTmpList(n).rmP(attnode);
1552         //_TH_ ^
1553         e -> atts[ndx] = toV(attnode);
1554         toV(attnode) -> ordinal = ndx;
1555         //_JP_ ^
1556       } else {
1557         //attnode.uri != replaced.uri
1558         if ( toA(attnode)->name.getPrefix() != UNDEF_PHRASE )
1559           SE( __SDOM_touchNS(s, n, 
1560                              toA(attnode)->name.getPrefix(), 
1561                              toA(attnode)->name.getUri(),
1562                              NSKIND_PARENT, 1) );
1563 //      int ndx = e -> atts.findNdx(toA(*replaced)->name);
1564 //      toV(*replaced) -> parent = NULL;
1565 //      //_TH_ v
1566 //      getTmpList(n).append(*replaced);
1567 //      //_TH_ ^
1568 //      e -> atts[ndx] = toV(attnode);
1569         //_JP_ v
1570         int ndx = toV(*replaced) -> ordinal;
1571         toV(*replaced) -> parent = NULL;
1572         //_TH_ v
1573         getTmpList(n).append(*replaced);
1574         getTmpList(n).rmP(attnode);
1575         //_TH_ ^
1576         e -> atts[ndx] = toV(attnode);
1577         toV(attnode) -> ordinal = ndx;
1578         //_JP_ ^
1579       };
1580     } else {
1581       //attr with the same prefix:local NOT found
1582       if ( toA(attnode)->name.getPrefix() != UNDEF_PHRASE )
1583         SE( __SDOM_touchNS(s, n, 
1584                            toA(attnode)->name.getPrefix(), 
1585                            toA(attnode)->name.getUri(),
1586                            NSKIND_PARENT, 0) );
1587       //_TH_ v
1588       getTmpList(n).rmP(attnode);
1589       //_TH_ ^
1590       e -> atts.append(toA(attnode));
1591     };
1592     toV(attnode) -> setParent(e);
1593     
1594   } else {
1595     // attnode is namespace
1596     int ndx = e -> namespaces.findNdx(toNS(attnode)->prefix);
1597     if (ndx != -1) {
1598       //namespace with the attnode.prefix exists
1599       NmSpace *nm = toNS(e -> namespaces[ndx]);
1600       if ( nm -> uri == toNS(attnode) -> uri ) {
1601         //namespace with attnode.prefix has attnode.uri
1602         //_TH_ v
1603         getTmpList(n).rmP(attnode);
1604         //_TH_ ^
1605         toV(nm) -> parent = NULL;
1606         //_TH_ v
1607         getTmpList(n).append(nm);
1608         //_TH_ ^
1609         e -> namespaces[ndx] = toV(attnode);
1610         toV(attnode) -> setParent(e);
1611         toV(attnode) -> ordinal = ndx;
1612         toNS(attnode)->kind = nm->kind;
1613         toNS(attnode)->usageCount = nm->usageCount;
1614         *replaced = (SDOM_Node)nm;
1615       } else {
1616         //namespace with attnode.prefix has NOT attnode.uri
1617         if ( nm -> usageCount != 0 || nm -> kind == NSKIND_DECLARED ) {
1618           // namespace used
1619           SDOM_Err(s, SDOM_NAMESPACE_ERR);
1620         } else {
1621           // namespace NOT used
1622           //_TH_ v
1623           getTmpList(n).rmP(attnode);
1624           //_TH_ ^
1625           toV(nm) -> parent = NULL;
1626           //_TH_ v
1627           getTmpList(n).append(nm);
1628           //_TH_ ^
1629           e -> namespaces[ndx] = toV(attnode);
1630           toV(attnode) -> setParent(e);
1631           toV(attnode) -> ordinal = ndx;
1632           toNS(attnode)->kind = NSKIND_DECLARED;
1633           toNS(attnode)->usageCount = 0;
1634           *replaced = (SDOM_Node)nm;
1635         };
1636       };
1637     } else {
1638       //namespace with attnode.prefix NOT exists
1639       *replaced = NULL;
1640       toNS(attnode)->kind = NSKIND_DECLARED;
1641       toNS(attnode)->usageCount = 0;
1642       //_TH_ v
1643       getTmpList(n).rmP(attnode);
1644       //_TH_ ^
1645       e -> namespaces.append(toNS(attnode));
1646       toV(attnode) -> setParent(e);
1647       SE( __SDOM_refreshNS(s, n, toNS(attnode)) );
1648     };
1649   };
1650   return SDOM_OK;           
1651 }
1652
1653 SDOM_Exception SDOM_setAttributeNodeNS(SablotSituation s, SDOM_Node n, SDOM_Node attnode, SDOM_Node *replaced)
1654 {
1655   if ( !( isElement(toV(n)) && (isAttr(toV(attnode)) 
1656                                 || isNS(toV(attnode))) ) )
1657     SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1658   if ( ownerDoc(n) != ownerDoc(attnode) )
1659     SDOM_Err(s, SDOM_WRONG_DOCUMENT_ERR);
1660   if ( toV(attnode) -> parent )
1661     SDOM_Err(s, SDOM_INUSE_ATTRIBUTE_ERR);
1662   Element *e = toE(toV(n));
1663   //NmSpace *nm;
1664   if ( isAttr(toV(attnode)) ) {
1665     Str attname;
1666     e -> getOwner().expandQStr(toA(attnode) -> getName(), attname);
1667     SE( SDOM_getAttributeNodeNS(s, n, 
1668                                 (SDOM_char*)(e -> getOwner().expand(toA(attnode)->name.getUri())), 
1669                                 (SDOM_char*)(e -> getOwner().expand(toA(attnode)->name.getLocal())),
1670                                 replaced) );
1671     if ( *replaced ) {
1672       //attr with the same uri:local found
1673       if ( toA(attnode)->name.getPrefix() == toA(*replaced)->name.getPrefix() ) {
1674         //the same prefix
1675 //      int ndx = e -> atts.findNdx(toA(*replaced)->name);
1676 //      toV(*replaced) -> parent = NULL;
1677 //      //_TH_ v
1678 //      getTmpList(n).append(*replaced);
1679 //      //_TH_ ^
1680 //      e -> atts[ndx] = toV(attnode);
1681         //_JP_ v
1682         int ndx = toV(*replaced) -> ordinal;
1683         toV(*replaced) -> parent = NULL;
1684         //_TH_ v
1685         getTmpList(n).append(*replaced);
1686         getTmpList(n).rmP(attnode);
1687         //_TH_ ^
1688         e -> atts[ndx] = toV(attnode);
1689         toV(attnode) -> ordinal = ndx;
1690         //_JP_ ^
1691
1692         //+++++++++++++++++
1693       } else {
1694         //attnode.prefix != replaced.prefix
1695         if ( toA(attnode)->name.getPrefix() != UNDEF_PHRASE )
1696           SE( __SDOM_touchNS(s, n, 
1697                              toA(attnode)->name.getPrefix(), 
1698                              toA(attnode)->name.getUri(),
1699                              NSKIND_PARENT, 1) );
1700         if ( toA(*replaced)->name.getPrefix() != UNDEF_PHRASE )
1701           e -> namespaces.decPrefixUsage(toA(*replaced)->name.getPrefix());
1702 //      int ndx = e -> atts.findNdx(toA(*replaced)->name);
1703 //      toV(*replaced) -> parent = NULL;
1704 //      //_TH_ v
1705 //      getTmpList(n).append(*replaced);
1706 //      //_TH_ ^
1707 //      e -> atts[ndx] = toV(attnode);
1708         //_JP_ v
1709         int ndx = toV(*replaced) -> ordinal;
1710         toV(*replaced) -> parent = NULL;
1711         //_TH_ v
1712         getTmpList(n).rmP(attnode);
1713         getTmpList(n).append(*replaced);
1714         //_TH_ ^
1715         e -> atts[ndx] = toV(attnode);
1716         toV(attnode) -> ordinal = ndx;
1717         //_JP_ ^
1718       };
1719     } else {
1720       //attr with the same uri:local NOT found
1721       if ( toA(attnode)->name.getPrefix() != UNDEF_PHRASE )
1722         SE( __SDOM_touchNS(s, n, 
1723                            toA(attnode)->name.getPrefix(), 
1724                            toA(attnode)->name.getUri(),
1725                            NSKIND_PARENT, 0) );
1726       //_TH_ v
1727       getTmpList(n).rmP(attnode);
1728       //_TH_ ^
1729       e -> atts.append(toA(attnode));
1730     };
1731     toV(attnode) -> setParent(e);
1732     
1733   } else {
1734     // attnode is namespace
1735     int ndx = e -> namespaces.findNdx(toNS(attnode)->prefix);
1736     if (ndx != -1) {
1737       //namespace with the attnode.prefix exists
1738       NmSpace *nm = toNS(e -> namespaces[ndx]);
1739       if ( nm -> uri == toNS(attnode) -> uri ) {
1740         //namespace with attnode.prefix has attnode.uri
1741         //_TH_ v
1742         getTmpList(n).rmP(attnode);
1743         //_TH_ ^
1744         toV(nm) -> parent = NULL;
1745         //_TH_ v
1746         getTmpList(n).append(nm);
1747         //_TH_ ^
1748         e -> namespaces[ndx] = toV(attnode);
1749         toV(attnode) -> setParent(e);
1750         toV(attnode) -> ordinal = ndx;
1751         toNS(attnode)->kind = nm->kind;
1752         toNS(attnode)->usageCount = nm->usageCount;
1753         *replaced = (SDOM_Node)nm;
1754       } else {
1755         //namespace with attnode.prefix has NOT attnode.uri
1756         if ( nm -> usageCount != 0 || nm -> kind == NSKIND_DECLARED ) {
1757           // namespace used
1758           return SDOM_NAMESPACE_ERR;
1759         } else {
1760           // namespace NOT used
1761           //_TH_ v
1762           getTmpList(n).rmP(attnode);
1763           //_TH_ ^
1764           toV(nm) -> parent = NULL;
1765           //_TH_ v
1766           getTmpList(n).append(nm);
1767           //_TH_ ^
1768           e -> namespaces[ndx] = toV(attnode);
1769           toV(attnode) -> setParent(e);
1770           toV(attnode) -> ordinal = ndx;
1771           toNS(attnode)->kind = NSKIND_DECLARED;
1772           toNS(attnode)->usageCount = 0;
1773           *replaced = (SDOM_Node)nm;
1774         };
1775       };
1776     } else {
1777       //namespace with attnode.prefix NOT exists
1778       *replaced = NULL;
1779       toNS(attnode)->kind = NSKIND_DECLARED;
1780       toNS(attnode)->usageCount = 0;
1781       //_TH_ v
1782       getTmpList(n).rmP(attnode);
1783       //_TH_ ^
1784       e -> namespaces.append(toNS(attnode));
1785       toV(attnode) -> setParent(e);
1786       SE( __SDOM_refreshNS(s, n, toNS(attnode)) );
1787     };
1788   };
1789   return SDOM_OK;           
1790 }
1791
1792
1793 SDOM_Exception SDOM_removeAttributeNode(SablotSituation s, SDOM_Node n, SDOM_Node attnode, SDOM_Node *removed)
1794 {
1795     if (!isElement(toV(n)))
1796         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1797     Element *e = toE(toV(n));
1798
1799     if (isAttr(attnode))
1800     {
1801         int attNdx = e -> atts.findNdx(toA(attnode)->name);
1802         if (attNdx != -1)
1803         {
1804             //_TH_ v
1805             Vertex *tmp = e -> atts[attNdx];
1806             //_TH_ ^
1807             tmp -> parent = NULL;
1808             e -> atts.rm(attNdx);
1809             //_TH_ v
1810             getTmpList(n).append(tmp);
1811             //_TH_ ^
1812             if (toA(tmp) -> name.getPrefix() != UNDEF_PHRASE)
1813                 e -> namespaces.decPrefixUsage(toA(tmp) -> name.getPrefix());
1814             *removed = tmp;
1815         } else {
1816           SDOM_Err(s, SDOM_NOT_FOUND_ERR);
1817         };
1818     }
1819     else
1820     {
1821         int attNdx = e -> namespaces.findNdx(toNS(attnode)->prefix);
1822         if (attNdx != -1)
1823         {
1824             if (toNS(e -> namespaces[attNdx]) -> usageCount != 0) 
1825                 SDOM_Err(s, SDOM_NO_MODIFICATION_ALLOWED_ERR);
1826             //_TH_ v
1827             Vertex *tmp = e -> namespaces[attNdx];
1828             //_TH_ ^
1829             tmp -> parent = NULL;
1830             e -> namespaces.rm(attNdx);
1831             //_TH_ v
1832             getTmpList(n).append(tmp);
1833             //_TH_ ^
1834             *removed = tmp;
1835         } else {
1836           SDOM_Err(s, SDOM_NOT_FOUND_ERR);
1837         };
1838     }
1839     return SDOM_OK;         
1840 }
1841 //_JP_ ^        
1842
1843
1844 SDOM_Exception SDOM_removeAttribute(SablotSituation s, SDOM_Node n, const SDOM_char *name)
1845 {
1846     QName q;
1847     if (!isElement(toV(n)))
1848         SDOM_Err(s, SDOM_INVALID_NODE_TYPE);
1849     Element *e = toE(toV(n));
1850
1851     e -> setLogical(SIT(s), q, name, FALSE);
1852     if (!isXMLNS_(q, e))
1853     {
1854         int attNdx = e -> atts.findNdx(q);
1855         if (attNdx != -1)
1856         {
1857             //_TH_ v
1858             Vertex *tmp = e -> atts[attNdx];
1859             //_TH_ ^
1860             e -> atts[attNdx] -> parent = NULL;
1861             e -> atts.rm(attNdx);
1862             //_TH_ v
1863             getTmpList(n).append(tmp);
1864             //_TH_ ^
1865             //_JP_ v
1866             if (toA(tmp) -> name.getPrefix() != UNDEF_PHRASE)
1867                 e -> namespaces.decPrefixUsage(toA(tmp) -> name.getPrefix());
1868             //_JP_ ^
1869         }
1870     }
1871     else
1872     {
1873         int attNdx = e -> namespaces.findNdx(
1874                         q.getLocal() != e -> getOwner().stdPhrase(PHRASE_XMLNS) ? 
1875                         q.getLocal() : UNDEF_PHRASE);
1876         if (attNdx != -1)
1877         {
1878             //_JP_ v
1879             if (toNS(e -> namespaces[attNdx]) -> usageCount != 0) 
1880                 return SDOM_NO_MODIFICATION_ALLOWED_ERR;
1881             //_JP_ ^
1882             e -> namespaces[attNdx] -> parent = NULL;
1883             e -> namespaces.rm(attNdx);
1884         }       
1885     }
1886     return SDOM_OK;         
1887 }
1888
1889
1890 SDOM_Exception SDOM_getAttributeElement(SablotSituation s, SDOM_Node attr, SDOM_Node *owner)
1891 {
1892   Vertex *v = toV(attr);
1893   if ( isAttr(v) | isNS(v) )
1894     {
1895       *owner = v -> parent;
1896       return SDOM_OK;
1897     }
1898   else
1899     return SDOM_HIERARCHY_REQUEST_ERR;
1900 }
1901
1902 SDOM_Exception SDOM_getAttributeList(SablotSituation s, SDOM_Node n, SDOM_NodeList *pAttrList)
1903 {
1904     *pAttrList = new CList;
1905     if (isElement(toV(n)))
1906     {
1907         int i;
1908         NSList& namespaces = toE(toV(n)) -> namespaces;
1909             for (i = 0; i < namespaces.number(); i++)
1910                 ((CList*)(*pAttrList)) -> append(namespaces[i]);
1911         AttList& atts = toE(toV(n)) -> atts;
1912             for (i = 0; i < atts.number(); i++)
1913                 ((CList*)(*pAttrList)) -> append(atts[i]);
1914     }    
1915     return SDOM_OK;
1916 }
1917
1918 //
1919 //
1920 //
1921
1922 SDOM_Exception SDOM_docToString(SablotSituation s, SDOM_Document d, SDOM_char **pSerialized)
1923 {
1924     // using explicit temp because of BeOS
1925     char *serializedTemp = NULL;
1926     toTree(d) -> serialize(SIT(s), serializedTemp);
1927     *pSerialized = serializedTemp;
1928     return SDOM_OK;
1929 }
1930
1931 //_PH_
1932 SDOM_Exception SDOM_nodeToString(SablotSituation s, SDOM_Document d, 
1933                                  SDOM_Node n,
1934                                  SDOM_char **pSerialized)
1935 {
1936     char *serializedTemp = NULL;
1937     toTree(d) -> serializeNode(SIT(s), toE(n), serializedTemp);
1938     *pSerialized = serializedTemp;
1939     return SDOM_OK;
1940 }
1941
1942 //
1943 //
1944 //
1945
1946 SDOM_Exception SDOM_getNodeListLength(SablotSituation s, SDOM_NodeList l, int *pLength)
1947 {
1948     *pLength = ((CList*)l) -> number();
1949     return SDOM_OK;
1950 }
1951
1952 SDOM_Exception SDOM_getNodeListItem(SablotSituation s, SDOM_NodeList l, int index, SDOM_Node *pItem)
1953 {
1954     if ((index < 0) || (index >= ((CList*)l) -> number()))
1955         SDOM_Err(s, SDOM_INDEX_SIZE_ERR);
1956     *pItem = ((CList*)l) -> operator[](index);
1957     return SDOM_OK;
1958 }
1959
1960 SDOM_Exception SDOM_disposeNodeList(SablotSituation s, SDOM_NodeList l)
1961 {
1962     if (!((CList*)l) -> decRefCount())
1963         delete (CList*)l;
1964         return SDOM_OK;
1965 }
1966
1967
1968 //
1969 //
1970 //
1971
1972 SDOM_Exception SDOM_xql(SablotSituation s, const SDOM_char *query, SDOM_Node currentNode, SDOM_NodeList *pResult)
1973 {
1974     RootNode &root = toV(currentNode) -> getOwner().getRoot();
1975     
1976     // find the document element
1977     int i;
1978     for (i = 0; i < root.contents.number(); i++)
1979         if (isElement(root.contents[i])) break;
1980         
1981     Element *docElement = (i < root.contents.number()) ?
1982         toE(root.contents[i]) : &root;
1983     Expression queryEx(*docElement);
1984     *pResult = NULL;
1985     
1986     // parse the query string as a non-pattern
1987     if (queryEx.parse(SIT(s), (char*)query, FALSE, TRUE))
1988         SDOM_Err(s, SDOM_QUERY_PARSE_ERR);
1989                 
1990         // create an initial context
1991     GP( Context ) dummy = new Context(NULL); //_cn_ no current node
1992     GP( Context ) c;
1993     c.assign(dummy);
1994     (*c).set(toV(currentNode));
1995         
1996         // create the result context
1997         if (queryEx.createContext(SIT(s), c))
1998         SDOM_Err(s, SDOM_QUERY_EXECUTION_ERR);
1999         
2000         // preserve the CList
2001         (*c).getArrayForDOM() -> incRefCount();
2002     c.unkeep();
2003         *pResult = (SDOM_NodeList) (*c).getArrayForDOM();
2004     return SDOM_OK;
2005 }
2006
2007 SDOM_Exception SDOM_xql_ns(SablotSituation s, const SDOM_char *query, SDOM_Node currentNode, char** nsmap, SDOM_NodeList *pResult)
2008 {
2009   //RootNode &root = toV(currentNode) -> getOwner().getRoot();
2010     
2011   // find the document element
2012   //int i;
2013   //for (i = 0; i < root.contents.number(); i++)
2014   //    if (isElement(root.contents[i])) break;
2015   GP( Tree ) tree = new Tree(Str("noscheme:dummy-tree"), false);
2016   QName q; 
2017   q.setLocal((*tree).unexpand(Str("dummy-root")));
2018   Element *e = new(&((*tree).getArena())) Element(*tree, q);
2019   e -> setSubtreeInfo((*tree).getRootSubtree());
2020   char ** aux = nsmap;
2021   while (*aux) {
2022     char *pref = *aux;
2023     char *uri = *(aux + 1);
2024     NmSpace *nm = new(&((*tree).getArena())) 
2025       NmSpace(*tree, (*tree).unexpand(pref), (*tree).unexpand(uri),
2026               false, NSKIND_DECLARED);
2027     e -> newChild(SIT(s), nm);
2028     aux += 2;
2029   }
2030         
2031   Expression queryEx(*e);
2032   *pResult = NULL;
2033   
2034   // parse the query string as a non-pattern
2035   if (queryEx.parse(SIT(s), (char*)query, FALSE, TRUE))
2036     SDOM_Err(s, SDOM_QUERY_PARSE_ERR);
2037   
2038   // create an initial context
2039   GP( Context ) dummy = new Context(NULL); //_cn_ no current node
2040   GP( Context ) c;
2041   c.assign(dummy);
2042   (*c).set(toV(currentNode));
2043   
2044   // create the result context
2045   if (queryEx.createContext(SIT(s), c))
2046     SDOM_Err(s, SDOM_QUERY_EXECUTION_ERR);
2047   
2048   // preserve the CList
2049   (*c).getArrayForDOM() -> incRefCount();
2050   c.unkeep();
2051   *pResult = (SDOM_NodeList) (*c).getArrayForDOM();
2052   return SDOM_OK;
2053 }
2054
2055 //
2056 //    exception retrieval
2057 //
2058
2059 int SDOM_getExceptionCode(SablotSituation s)
2060 {
2061     return SIT(s).getSDOMExceptionCode();
2062 }
2063
2064 char* SDOM_getExceptionMessage(SablotSituation s)
2065 {
2066     return SDOM_newString(
2067         SDOM_ExceptionMsg[SDOM_getExceptionCode(s)]);
2068 }
2069
2070 void SDOM_getExceptionDetails(
2071     SablotSituation s,
2072     int *code,
2073     char **message,
2074     char **documentURI,
2075     int *fileLine)
2076 {
2077     Str message_, documentURI_;
2078     MsgCode code_;
2079     int fileLine_;
2080     SIT(s).getSDOMExceptionExtra(code_, message_, documentURI_, fileLine_);
2081     *code = code_;
2082     *fileLine = fileLine_;
2083     *documentURI = SDOM_newString(documentURI_);
2084     *message = SDOM_newString(message_);
2085 }
2086
2087
2088
2089 //
2090 //    internal
2091 //
2092
2093 void SDOM_setNodeInstanceData(SDOM_Node n, void *data)
2094 {
2095     toV(n) -> setInstanceData(data);
2096 }
2097
2098 void* SDOM_getNodeInstanceData(SDOM_Node n)
2099 {
2100     return toV(n) -> getInstanceData();
2101 }
2102
2103 void SDOM_setDisposeCallback(SDOM_NodeCallback *f)
2104 {
2105     theDisposeCallback = f;
2106 }
2107
2108 SDOM_NodeCallback* SDOM_getDisposeCallback()
2109 {
2110     return theDisposeCallback;
2111 }
2112
2113
2114
2115 //_TH_ v
2116 void SDOM_tmpListDump(SDOM_Document doc, int p)
2117 {
2118   getTmpList(doc).dump(p);
2119 }
2120 //_TH_ ^
2121
2122 SDOM_Exception SDOM_compareNodes(SablotSituation s, SDOM_Node n1, SDOM_Node n2, int *res)
2123 {
2124   if (&(toV(n1) -> getOwner()) == &(toV(n2) -> getOwner()) ) //the same owner
2125     {
2126       int s1 = toV(n1) -> stamp;
2127       int s2 = toV(n2) -> stamp;
2128       if (s1 < s2)
2129         *res = -1;
2130       else if (s1 == s2)
2131         *res = 0;
2132       else 
2133         *res = 1;
2134     }
2135   else
2136     {
2137       *res = strcmp( (char*)(toV(n1) -> getOwner().getURI()),
2138                      (char*)(toV(n2) -> getOwner().getURI()) );
2139     }
2140   return SDOM_OK;
2141 }
2142
2143 #endif /* ENABLE_DOM */