Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: diffxml/Patch/Patch.java


1   /*
2   Program to apply a DUL patch
3    
4   Copyright (C) 2002  Adrian Mouat
5    
6   This program is free software; you can redistribute it and/or
7   modify it under the terms of the GNU General Public License
8   as published by the Free Software Foundation; either version 2
9   of the License, or (at your option) any later version.
10   
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15  
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19   
20  Author: Adrian Mouat
21  email: amouat@postmaster.co.uk
22  */
23  package diffxml.Patch;
24  
25  
26  /*
27  Program to apply DUL patches
28  */
29  
30  import diffxml.*;
31  
32  import org.apache.xpath.XPathAPI;
33  import org.w3c.dom.Document;
34  import org.w3c.dom.Element;
35  import org.w3c.dom.Node;
36  import org.w3c.dom.NodeList;
37  import org.w3c.dom.traversal.*;
38  import org.apache.xerces.parsers.DOMParser;
39  import org.w3c.dom.NamedNodeMap;
40  import javax.xml.transform.TransformerException;
41  import org.apache.xerces.dom3.Node3;
42  import javax.xml.transform.*;
43  import javax.xml.transform.stream.*;
44  import javax.xml.transform.dom.*;
45  import org.xml.sax.SAXException;
46  import java.io.File;
47  
48  public class Patch
49  {
50  static boolean reverse=false;
51  
52  //Currently breaks from unix patch, file not implicitly written to
53  //To change this set the boolean dryrun to false
54  //You will then need to use -dry-run to avoid overwriting files
55  
56  static boolean dryrun=true;
57  static String file1;
58  static String file2;
59  
60  public static void parseArgs(String[] args)
61  {
62  int i=0;
63  char flag;
64  String arg;
65  
66  while (i < args.length && args[i].startsWith("-"))
67          {
68          arg = args[i++];
69   
70          //Normalize multiple dashes
71          //Don't understand point in differentiating between 1 and 2 dashes
72          //We allow 2 in order to mimic patch util
73   
74          if (arg.startsWith("--"))
75                  arg=arg.substring(1);
76   
77          //"wordy" arguments
78          if (arg.equals("-version"))
79              printVersion();
80          else if (arg.equals("-help"))
81              printHelp();
82          else if (arg.equals("-dry-run"))
83              dryrun=true;
84    else if (arg.equals("-reverse"))
85        reverse=true;
86  
87    //(series of) flag arguments
88          else 
89        {
90               for (int j = 1; j < arg.length(); j++) 
91      {
92                  flag = arg.charAt(j);
93                  switch (flag) 
94          {
95                      case 'V':
96                          printVersion();
97                          break;
98          case 'h':
99        printHelp();
100         case 'd':
101       dryrun=true;
102         case 'R':
103       reverse=true;
104         
105         default:
106       System.err.println("Patch: illegal option " + flag);
107                         System.exit(2);
108                         break;
109         }
110     }
111       }
112   }
113 if ((i+2) != args.length)
114         printUsage();
115  
116 file1=args[i];
117 //db.p("file1= " + file1);
118 file2=args[++i];
119 //db.p("file2= " + file2);
120         
121 }
122 
123 public static void printUsage()
124 {
125 System.err.println("Usage: patch [OPTION]... [ORIGFILE [PATCHFILE]]");
126 System.exit(2);
127 }
128 
129 public static void printHelp()
130 {
131 System.out.print("\nUsage: patch [OPTION]... [ORIGFILE [PATCHFILE]]\n\nApply a diffxml file to one of the original XML files.\n\n --version  -V  Output version number of program.\n --help     -h  Print summary of options and exit. \n --dry-run  -d  Print results of applying the changes without modifying any files. \n --reverse  -R  Assume that the delta file was created with the old and new files swapped.\n\tAttempt to reverse sense of change before applying it, e.g. inserts become deletes.\n\n");
132 System.out.print("\nThis product includes software developed by the Indiana University Extreme! Lab (http://www.extreme.indiana.edu/).\n\n");
133 System.out.print("\nThis product includes software developed by the Apache Software Foundation (http://www.apache.org/).\n\n");
134 System.exit(0);
135 }
136 
137 public static void printVersion()
138 {
139 System.out.println("patchxml Version 0.9");
140 System.out.print("\nThis product includes software developed by the Indiana University Extreme! Lab (http://www.extreme.indiana.edu/).\n");
141 System.out.print("\nThis product includes software developed by the Apache Software Foundation (http://www.apache.org/).\n\n");
142 System.exit(0);
143 }
144 
145                                                                                                                      
146 public void apply(Document doc, Document patch)
147 {
148 NodeIterator ni = ((DocumentTraversal) patch).createNodeIterator
149       (patch.getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, false);
150 
151 Node op = ni.nextNode();
152 //Check we have a delta
153 if (!op.getNodeName().equals("delta"))
154   {
155   System.err.println("Not a delta document!");
156   return;
157   }
158 
159 //Cycle through elements apply ops
160 op = ni.nextNode();
161 
162 int instr=0;
163 while (op!=null)
164   {
165   String op_name=op.getNodeName();
166   NamedNodeMap op_attrs=op.getAttributes();
167   instr++;
168   db.p(instr + " " + op);
169   /*
170   if (op_name.equals("update"))
171     {
172     Node node;  
173     try {
174       node=XPathAPI.selectSingleNode
175         (doc.getDocumentElement(), op_attrs.getNamedItem("node").getNodeValue());
176 
177       //Currently all update does is change the name
178       //This actually breaks the DUL but its a quick hack to get things working
179 
180       Element new_node=doc.createElement(op_attrs.getNamedItem("name").getNodeValue());
181       
182         }
183     catch (TransformerException e)
184                         { System.err.println("Could not resolve XPath for parent for update");}
185     }
186   */
187   if (op_name.equals("insert"))
188     {
189     db.p("Applying insert");
190     /*
191     ============
192     Apply Insert
193     ============
194     */
195     //For all NodeTypes, find parent
196     Node parent;
197     Node ins;
198     try {
199     parent=XPathAPI.selectSingleNode
200       (doc.getDocumentElement(), op_attrs.getNamedItem("parent").getNodeValue());
201     db.p("Insert as child of " + parent.getNodeName());
202 
203     //Different ops dependent on NodeType being inserted
204     
205     
206     int type=new Integer( op_attrs.getNamedItem("nodetype").getNodeValue() ).intValue();
207     //Note setting cn to 0 
208     int xpath_cn=0;
209     int dom_cn=0;
210     if (op_attrs.getNamedItem("childno") != null)
211       xpath_cn=new Integer( op_attrs.getNamedItem("childno").getNodeValue() ).intValue();
212 
213     //Convert xpath childno to DOM childno
214 
215     //Need child nodes in all cases but attr
216     //dom_cn needs to store *first* node eqv to XPath
217     NodeList doc_kids = parent.getChildNodes();
218     if (type!=Node.ATTRIBUTE_NODE)
219       {
220       int index=0;
221       int j;
222       for (j=0;j<doc_kids.getLength();j++)
223         {
224         index++;    
225         if (j>0 && doc_kids.item(j).getNodeType()==Node.TEXT_NODE 
226           && doc_kids.item(j-1).getNodeType()==Node.TEXT_NODE)
227           index--;
228         if (index==xpath_cn)
229           break;
230         }
231       dom_cn=j;  
232       
233       }
234 
235     //Get value to insert if any
236     String value="";
237     NodeList op_kids = op.getChildNodes();
238 
239     if (op_kids.getLength() > 1)
240       System.err.println("Unexpected kiddy winkles in insert operation");
241     else if ( (op_kids.getLength() == 1) && (op_kids.item(0).getNodeType()==Node.TEXT_NODE) )
242       value=op_kids.item(0).getNodeValue();
243       
244     int charpos=1;
245                 if (op_attrs.getNamedItem("charpos") != null)
246                         charpos=new Integer( op_attrs.getNamedItem("charpos").getNodeValue() ).intValue();
247     boolean append=false;  
248     switch (type)
249       {
250       case Node.TEXT_NODE:
251         ins=doc.createTextNode(value);
252         db.p("dom_cn=" + dom_cn + " Inserting text: " + value);
253         //careful with cn
254         if (dom_cn==doc_kids.getLength() &&
255                                         doc_kids.item(dom_cn-1).getNodeType()==Node.TEXT_NODE)
256                                         {
257                                         if (charpos<=1)
258                                                 {
259                                                 //Assume we actually mean to append node
260                                                 append=true;
261                                                 }
262                                         else
263                                                 {
264                                                 //Move back to the start of the text nodes
265                                                 while (dom_cn>0 && doc_kids.item(dom_cn-1).getNodeType()==Node.TEXT_NODE)
266                                                         dom_cn--;
267  
268                                                 //move to charpos
269                                                 while ( charpos>doc_kids.item(dom_cn).getNodeValue().length())
270                                                         {
271                                                         charpos=charpos-doc_kids.item(dom_cn).getNodeValue().length();
272                                                         dom_cn++;
273                                                         if (dom_cn==doc_kids.getLength() || doc_kids.item(dom_cn).getNodeType()!=Node.TEXT_NODE)
274                                                                 {
275                                                                 //System.err.println("charpos beyond end of text");
276                                                                 append=true;
277                                                                 parent.appendChild(ins);
278                                                                 break;
279                                                                 }
280                                                         }
281                                                 }
282                                         if (!append)
283                                                 parent.insertBefore(ins,doc_kids.item(dom_cn));
284  
285                                         }
286         else if (doc_kids.getLength()>(dom_cn) )
287           {
288           //We have a node to insert before
289           //Do the charpos thingy.
290           if (doc_kids.item(dom_cn).getNodeType()==Node.TEXT_NODE)
291             {
292             //dom_cn is first text node
293             //move to charpos
294             while ( charpos>doc_kids.item(dom_cn).getNodeValue().length())
295               {  
296               charpos=charpos-doc_kids.item(dom_cn).getNodeValue().length();
297               dom_cn++;
298               if (dom_cn==doc_kids.getLength() || doc_kids.item(dom_cn).getNodeType()!=Node.TEXT_NODE)
299                 {
300                 System.err.println("charpos beyond end of text");
301                 append=true;
302                 parent.appendChild(ins);
303                 break;
304                 }
305               }
306             //charpos in current node.
307             //Won't consider splitting nodes at mo as unneccesary
308             }
309           if ( charpos!=1)
310             System.err.println("charpos seems to be out");
311           if (!append)
312             parent.insertBefore(ins,doc_kids.item(dom_cn));
313           }
314         else
315           parent.appendChild(ins);
316         break;
317       case Node.ELEMENT_NODE:
318         String tag=op_attrs.getNamedItem("name").getNodeValue();
319         
320         ins=doc.createElement(tag);
321         if (dom_cn==doc_kids.getLength() && 
322           doc_kids.item(dom_cn-1).getNodeType()==Node.TEXT_NODE)
323           {
324           if (charpos<=1)  
325             {
326             //Assume we actually mean to append node
327             append=true;
328             }
329           else 
330             {
331             //Move back to the start of the text nodes
332             while (dom_cn>0 && doc_kids.item(dom_cn-1).getNodeType()==Node.TEXT_NODE) 
333               dom_cn--;
334 
335             //move to charpos
336             while ( charpos>doc_kids.item(dom_cn).getNodeValue().length())
337                                                         {
338                                                         charpos=charpos-doc_kids.item(dom_cn).getNodeValue().length();
339                                                         dom_cn++;
340                                                         if (dom_cn==doc_kids.getLength() || doc_kids.item(dom_cn).getNodeType()!=Node.TEXT_NODE)
341                                                                 {
342                                                                 //System.err.println("charpos beyond end of text");
343                                                                 append=true;
344                                                                 parent.appendChild(ins);
345                                                                 break;
346                                                                 }
347                                                         }  
348             }  
349           if (!append)
350                                                 parent.insertBefore(ins,doc_kids.item(dom_cn));
351         
352           }
353         else if (doc_kids.getLength()>(dom_cn))
354                                         {
355                                         //We have a node to insert before
356                                         //Do the charpos thingy.
357                                         if (doc_kids.item(dom_cn).getNodeType()==Node.TEXT_NODE)
358                                                 {
359                                                 //dom_cn is first text node
360                                                 //move to charpos
361                                                 while ( charpos>doc_kids.item(dom_cn).getNodeValue().length())
362                                                         {
363                                                         charpos=charpos-doc_kids.item(dom_cn).getNodeValue().length();
364                                                         dom_cn++;
365                                                         if ( dom_cn==doc_kids.getLength() || doc_kids.item(dom_cn).getNodeType()!=Node.TEXT_NODE)
366                 {
367                                                                 //System.err.println("charpos beyond end of text");
368                 append=true;
369                 parent.appendChild(ins);
370                 break;
371                 }
372                                                         }
373                                                 //charpos in current node.
374                                                 //Won't consider splitting nodes at mo as unneccesary
375                                                 }
376           if (!append)
377                                           parent.insertBefore(ins,doc_kids.item(dom_cn));
378                                         }
379                                 else
380                                         parent.appendChild(ins);  
381         break;
382       case Node.COMMENT_NODE:
383         ins=doc.createComment(value);
384         if (dom_cn==doc_kids.getLength() &&
385                                         doc_kids.item(dom_cn-1).getNodeType()==Node.TEXT_NODE)
386                                         {
387                                         if (charpos<=1)
388                                                 {
389                                                 //Assume we actually mean to append node
390                                                 append=true;
391                                                 }
392                                         else
393                                                 {
394                                                 //Move back to the start of the text nodes
395                                                 while (dom_cn>0 && doc_kids.item(dom_cn-1).getNodeType()==Node.TEXT_NODE)
396                                                         dom_cn--;
397  
398                                                 //move to charpos
399                                                 while ( dom_cn==doc_kids.getLength() || charpos>doc_kids.item(dom_cn).getNodeValue().length())
400                                                         {
401                                                         charpos=charpos-doc_kids.item(dom_cn).getNodeValue().length();
402                                                         dom_cn++;
403                                                         if (doc_kids.item(dom_cn).getNodeType()!=Node.TEXT_NODE)
404                                                                 {
405                                                                 //System.err.println("charpos beyond end of text");
406                                                                 append=true;
407                                                                 parent.appendChild(ins);
408                                                                 break;
409                                                                 }
410                                                         }
411                                                 }
412                                         if (!append)
413                                                 parent.insertBefore(ins,doc_kids.item(dom_cn));
414  
415                                         }
416         else if (doc_kids.getLength()>(dom_cn) )
417                                         {
418                                         //We have a node to insert before
419                                         //Do the charpos thingy.
420                                         if (doc_kids.item(dom_cn).getNodeType()==Node.TEXT_NODE)
421                                                 {
422                                                 //dom_cn is first text node
423                                                 //move to charpos
424                                                 while ( charpos>doc_kids.item(dom_cn).getNodeValue().length())
425                                                         {
426                                                         charpos=charpos-doc_kids.item(dom_cn).getNodeValue().length();
427                                                         dom_cn++;
428                                                         if (dom_cn==doc_kids.getLength() || doc_kids.item(dom_cn).getNodeType()!=Node.TEXT_NODE)
429                 {
430                                                                 //System.err.println("charpos beyond end of text");
431                 append=true;
432                 parent.appendChild(ins);
433                 break;
434                 }
435                                                         }
436                                                 //charpos in current node.
437                                                 //Won't consider splitting nodes at mo as unneccesary
438                                                 }
439           if (!append)
440                                           parent.insertBefore(ins,doc_kids.item(dom_cn));
441                                         }
442                                 else
443                                         parent.appendChild(ins);
444                                 break;  
445       case Node.ATTRIBUTE_NODE:
446         String name=op_attrs.getNamedItem("name").getNodeValue();
447         ( (Element) parent).setAttribute(name, value);
448         break;
449       default:
450         System.err.println("Unknown NodeType " + type);
451         return;
452       }  
453           
454         
455     } catch (TransformerException e) 
456       { System.err.println("Could not resolve XPath for parent for insert");}
457 
458     }
459   else if (op_name.equals("delete"))
460     {
461     /*=============
462     Applying Delete
463     =============*/
464     db.p("Applying delete");
465     try {
466       //According to API returns *first* match, so should be first text node if text node matched
467       Node3 del_node=(Node3) XPathAPI.selectSingleNode
468                           (doc.getDocumentElement(), op_attrs.getNamedItem("node").getNodeValue());
469 
470       if (del_node==null)
471         {
472         System.err.println("Could not find node to delete " + op_attrs.getNamedItem("node").getNodeValue());
473         break;
474         }
475       int charpos=1;
476                   if (op_attrs.getNamedItem("charpos") != null)
477                            charpos=new Integer( op_attrs.getNamedItem("charpos").getNodeValue() ).intValue();
478 
479       //Currently only consider deleting nodes, not part of nodes
480       if (del_node.getNodeType()==Node.TEXT_NODE)
481         {
482         //Get del_node as item of parents child nodelist
483         NodeList del_nodelist=del_node.getParentNode().getChildNodes();
484         int i=0;
485         while ( !del_node.isSameNode(del_nodelist.item(i)) )
486           i++;
487 
488         /*
489         while (charpos>0)
490           {  
491           charpos=charpos-del_nodelist.item(i).getNodeValue().length();
492           i++;
493           }
494         */
495         while (charpos>del_nodelist.item(i).getNodeValue().length())
496           {
497           charpos=charpos-del_nodelist.item(i).getNodeValue().length();
498           i++;
499           }
500         del_node=(Node3) del_nodelist.item(i);  
501         }
502       db.p("Deleting node " + del_node.getNodeName() + " " + del_node.getNodeValue() );
503       if (op_attrs.getNamedItem("length") != null)
504         {
505         db.p("Supposed length " + op_attrs.getNamedItem("length").getNodeValue());
506         db.p("Actual length " + del_node.getNodeValue().length());
507         }
508         
509       del_node.getParentNode().removeChild(del_node);
510 
511     } catch (TransformerException e)
512       { System.err.println("Could not resolve XPath for node to be deleted");}
513 
514     }
515   else if (op_name.equals("move"))
516     {
517     db.p("Applying move");
518     /*=========
519     Apply Move
520     =========*/
521     db.p("Node: " + op_attrs.getNamedItem("node").getNodeValue() + " Parent" + op_attrs.getNamedItem("parent").getNodeValue());
522     db.p("childno" + op_attrs.getNamedItem("childno").getNodeValue());
523     if (op_attrs.getNamedItem("length") != null)
524       db.p("length " + op_attrs.getNamedItem("length").getNodeValue());
525       
526     //First find the node
527     try {
528       Node3 mov_node=(Node3) XPathAPI.selectSingleNode
529                                 (doc.getDocumentElement(), op_attrs.getNamedItem("node").getNodeValue());
530  
531                         if (mov_node==null)
532                                 System.err.println("Could not find node to move " + op_attrs.getNamedItem("node").getNodeValue());
533  
534                         int old_charpos=1;
535                         if (op_attrs.getNamedItem("old_charpos") != null)
536                                 old_charpos=new Integer( op_attrs.getNamedItem("old_charpos").getNodeValue() ).intValue(); 
537       db.p("old_charpos= " +old_charpos);
538     
539   
540                         //Currently only consider deleting nodes, not part of nodes
541                         if (mov_node.getNodeType()==Node.TEXT_NODE)
542                                 {
543                                 //Get del_node as item of parents child nodelist
544                                 NodeList mov_nodelist=mov_node.getParentNode().getChildNodes();
545                                 int i=0;
546                                 while ( !mov_node.isSameNode(mov_nodelist.item(i)) )
547                                         i++;
548  
549         db.p("i=" +i + " max=" + mov_nodelist.getLength());
550         db.p("length matched node=" + mov_node.getNodeValue().length());
551         if (op_attrs.getNamedItem("length") != null)
552           db.p("Supposed length=" + op_attrs.getNamedItem("length").getNodeValue().length());
553         if (i>0 && mov_nodelist.item(i-1).getNodeType()==Node.TEXT_NODE)
554                                         System.err.println("Failed to find leftmost text node for match");
555 
556                                 while (old_charpos>1)
557                                         {
558           db.p("old_charpos="+old_charpos);
559           db.p("length="+mov_nodelist.item(i).getNodeValue().length());
560                                         old_charpos=old_charpos-mov_nodelist.item(i).getNodeValue().length();
561                                         i++;
562           /*
563           if (i==mov_nodelist.getLength())
564             i--;
565           */
566           if (i==mov_nodelist.getLength() || mov_nodelist.item(i).getNodeType()!=Node.TEXT_NODE)
567             break;
568           //Probably want to check not greater than 1 b4 break
569                                         }
570 
571         if (i==mov_nodelist.getLength())
572           {
573           System.err.println("Something looks wrong in move"); 
574           i--;
575           }
576 
577          if (op_attrs.getNamedItem("length") != null)
578                                         db.p("Supposed length=" + op_attrs.getNamedItem("length").getNodeValue().length());
579         
580                                 mov_node=(Node3) mov_nodelist.item(i);
581         if (mov_node==null)
582           System.err.println("old_charpos past end of text node");
583 
584         if (op_attrs.getNamedItem("length")!=null)
585                                         if (mov_node.getNodeValue().length()!=op_attrs.getNamedItem("length").getNodeValue().length())
586             {
587                                                 System.err.println("!!!!!!!!!\nMoving Wrong Text Node\n!!!!!!!!!");
588             System.err.println("i=" + i);
589             System.err.println("Actual length" + mov_node.getNodeValue().length());
590             }
591                                 }
592 
593       //Find position to move to
594       //Get parent
595       Node parent=XPathAPI.selectSingleNode
596                           (doc.getDocumentElement(), op_attrs.getNamedItem("parent").getNodeValue());
597 
598       //Get XPath childno
599       int xpath_cn=0;
600       if (op_attrs.getNamedItem("childno") != null)
601                           xpath_cn=new Integer( op_attrs.getNamedItem("childno").getNodeValue() ).intValue();
602 
603       //Convert to DOM childno
604 
605       NodeList doc_kids = parent.getChildNodes();
606       int index=0;
607       int dom_cn=0;
608                         int j;
609                         for (j=0;j<doc_kids.getLength();j++)
610                                 {
611                                 index++;
612                                 if (j>0 && doc_kids.item(j).getNodeType()==Node.TEXT_NODE
613                                         && doc_kids.item(j-1).getNodeType()==Node.TEXT_NODE)
614                                         index--;
615                                 if (index==xpath_cn)
616                                         break;
617                                 }
618                         dom_cn=j;
619 
620       //Get new charpos
621       int new_charpos=1;
622                         if (op_attrs.getNamedItem("new_charpos") != null)
623                                 new_charpos=new Integer( op_attrs.getNamedItem("new_charpos").getNodeValue() ).intValue();
624       db.p("new_charpos" + new_charpos);
625 
626       //Perform insert
627       //Remove should happen automagically
628       //Need to check children are moved properly
629       boolean append=false; 
630       if (dom_cn==doc_kids.getLength() && doc_kids.getLength()!=0 &&
631                                         doc_kids.item(dom_cn-1).getNodeType()==Node.TEXT_NODE)
632                                         {
633                                         if (new_charpos<=1)
634                                                 {
635                                                 //Assume we actually mean to append node
636                                                 append=true;
637                                                 }
638                                         else
639                                                 {
640                                                 //Move back to the start of the text nodes
641                                                 while (dom_cn>0 && doc_kids.item(dom_cn-1).getNodeType()==Node.TEXT_NODE)
642                                                         dom_cn--;
643  
644                                                 //move to charpos
645                                                 while ( new_charpos>doc_kids.item(dom_cn).getNodeValue().length())
646                                                         {
647                                                         new_charpos=new_charpos-doc_kids.item(dom_cn).getNodeValue().length();
648                                                         dom_cn++;
649                                                         if (dom_cn==doc_kids.getLength() || doc_kids.item(dom_cn).getNodeType()!=Node.TEXT_NODE)
650                                                                 {
651                                                                 //System.err.println("charpos beyond end of text");
652                                                                 append=true;
653                                                                 parent.appendChild(mov_node);
654                                                                 break;
655                                                                 }
656                                                         }
657                                                 }
658                                         if (!append)
659                                                 parent.insertBefore(mov_node,doc_kids.item(dom_cn));
660  
661                                         }
662       else if (doc_kids.getLength()>(dom_cn) )
663                           {
664                                 //We have a node to insert before
665                                 //Do the charpos thingy.
666                                 if (doc_kids.item(dom_cn).getNodeType()==Node.TEXT_NODE)
667                                   {
668                                         //dom_cn is first text node
669                                         //move to charpos
670                                                 while ( new_charpos>doc_kids.item(dom_cn).getNodeValue().length())
671                                                         {
672                                                         new_charpos=new_charpos-doc_kids.item(dom_cn).getNodeValue().length();
673                                                         dom_cn++;
674                                                         if (doc_kids.item(dom_cn).getNodeType()!=Node.TEXT_NODE)
675                 {
676                                                                 //System.err.println("charpos beyond end of text");
677                 append=true;
678                 if (new_charpos != 1)
679                   System.err.println("Don't think charpos should be that....");
680                 //Want to append the node
681                 parent.appendChild(mov_node);
682                 break;
683                 }
684                                                         }
685                                                 //charpos in current node.
686                                                 //Won't consider splitting nodes at mo as unneccesary
687                                                 }
688           if (!append)
689                                           parent.insertBefore(mov_node,doc_kids.item(dom_cn));
690                                         }
691                                 else
692                                         parent.appendChild(mov_node);
693       } catch (TransformerException e)
694                           { System.err.println("Could not resolve XPath for node to be deleted");}
695     }  
696   else
697     {
698     System.err.println("Do not recognise element: " + op_name);
699     System.exit(2);
700     }
701   if (db.on)
702     {
703     try {
704     Transformer serializer = TransformerFactory.newInstance().newTransformer();
705           serializer.transform(new DOMSource(doc), new StreamResult(System.out));
706           System.out.println();
707     } catch (javax.xml.transform.TransformerException e) {}
708     }
709   op=ni.nextNode();  
710   }
711 
712 }
713 public static void main(String[] args)
714 {
715  
716 parseArgs(args);
717 //Check files exist
718 File test=new File(file1);
719 if (!test.exists())
720         {
721         System.err.println("Could not find file: " +file1);
722         System.exit(2);
723         }
724 test=new File(file2);
725 if (!test.exists())
726         {
727         System.err.println("Could not find file: " +file2);
728         System.exit(2);
729         }
730 
731 //db.on=true;
732 try
733 {
734         DOMParser parser1 = new DOMParser();
735         DOMParser parser2 = new DOMParser();
736 
737   
738   try {
739                    parser1.setFeature("http://xml.org/sax/features/external-general-entities",
740                                      false);
741                    parser2.setFeature("http://xml.org/sax/features/external-general-entities",
742                                      false);
743                    parser1.setFeature("http://xml.org/sax/features/external-parameter-entities",
744                                      false);
745                    parser2.setFeature("http://xml.org/sax/features/external-parameter-entities",
746                                      false);
747                    parser1.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar",
748                                      false);
749                    parser2.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar",
750                                      false);
751                    //parser1.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
752                    //                  false);
753                    parser2.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
754                                      false);
755                    parser1.setFeature("http://apache.org/xml/features/dom/create-entity-ref-nodes",
756                                      false);
757                    parser2.setFeature("http://apache.org/xml/features/dom/create-entity-ref-nodes",
758                                      false);
759                }
760         catch (SAXException e) {
761                    System.err.println("could not set parser feature");}
762   
763   parser1.parse(file1);
764   parser2.parse(file2);
765   Document doc=parser1.getDocument();
766   Document patch=parser2.getDocument();
767   doc.normalize();
768   patch.normalize();
769   if (reverse)
770     patch=Reverse.go(patch);
771   Patch p = new Patch();
772   p.apply(doc, patch);
773   //Write doc out to file again
774   Transformer serializer = TransformerFactory.newInstance().newTransformer();
775   if (dryrun)
776     serializer.transform(new DOMSource(doc), new StreamResult(System.out));
777   else
778     {
779     File f1=new File(file1);
780     serializer.transform(new DOMSource(doc), new StreamResult(f1));
781     }
782   //db.on=true;
783   db.p("Patch Doc");
784   if (db.on==true)  
785     serializer.transform(new DOMSource(patch), new StreamResult(System.out));
786   System.out.println();
787   //db.on=false;
788 }
789 catch (Exception e)
790         {
791         e.printStackTrace();
792         }
793 
794 }
795 }