Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that transforms an XML text document
4
 *             into a another type using XSL
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones
8
 *    Release: @release@
9
 *
10
 * '$Author: tao $'
11
 * '$Date: 2004-03-31 17:48:54 -0800 (Wed, 31 Mar 2004) $'
12
 * '$Revision: 2088 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28

    
29
package edu.ucsb.nceas.metacat;
30

    
31
import java.io.*;
32
import java.net.URL;
33
import java.net.MalformedURLException;
34
import java.sql.*;
35
import java.util.Enumeration;
36
import java.util.Hashtable;
37
import java.util.Stack;
38

    
39
import javax.xml.transform.TransformerFactory;
40
import javax.xml.transform.Transformer;
41
import javax.xml.transform.stream.StreamSource;
42
import javax.xml.transform.stream.StreamResult;
43
import javax.xml.transform.TransformerException;
44
import javax.xml.transform.TransformerConfigurationException;
45

    
46
import org.apache.xerces.parsers.DOMParser;
47
import org.w3c.dom.Attr;
48
import org.w3c.dom.NamedNodeMap;
49
import org.w3c.dom.NodeList;
50
import org.w3c.dom.Document;
51
import org.w3c.dom.Node;
52
import org.w3c.dom.NodeList;
53
import org.w3c.dom.DocumentType;
54
import org.xml.sax.SAXException;
55
import org.xml.sax.InputSource;
56
import org.apache.xerces.dom.DocumentTypeImpl;
57
import org.apache.xpath.XPathAPI;
58
import org.w3c.dom.NamedNodeMap;
59

    
60
/*
61
import oracle.xml.parser.v2.XSLStylesheet;
62
import oracle.xml.parser.v2.XSLException;
63
import oracle.xml.parser.v2.XMLParseException;
64
import oracle.xml.parser.v2.XSLProcessor;
65
import oracle.xml.parser.v2.XMLDocument;
66
import oracle.xml.parser.v2.DOMParser;
67
*/
68
import org.w3c.dom.Document;
69
import org.w3c.dom.Node;
70
import org.w3c.dom.Element;
71
import org.xml.sax.SAXException;
72

    
73
/**
74
 * A Class that transforms XML documents utitlizing XSL style sheets
75
 */
76
public class DBTransform {
77

    
78
  //private Connection	conn = null;
79
  private MetaCatUtil   util = null;
80
  private String 	configDir = null;
81
  private String	defaultStyle = null;
82

    
83
  /**
84
   * construct a DBTransform instance.
85
   *
86
   * Generally, one calls transformXMLDocument() after constructing the instance
87
   *
88
   * @param conn the database connection from which to lookup the public ids
89
   */
90
  public DBTransform()
91
                  throws IOException,
92
                         SQLException,
93
                         ClassNotFoundException
94
  {
95
    //this.conn = conn;
96
    util = new MetaCatUtil();
97
    configDir = util.getOption("config-dir");
98
    defaultStyle = util.getOption("default-style");
99
  }
100

    
101
  /**
102
   * @see transformXMLDocument(String doc, String sourceType,
103
   *            String targetType, String qformat, PrintWriter pw,
104
   *            String sessionid)
105
   */
106
  public void transformXMLDocument(String doc, String sourceType,
107
                String targetType, String qformat, PrintWriter pw,
108
                Hashtable param)
109
  {
110
    transformXMLDocument(doc, sourceType, targetType, qformat, pw, param, null);
111
  }
112

    
113
   /**
114
   * @see transformXMLDocument(String doc, String sourceType,
115
   *            String targetType, String qFormat, StringWriter pw
116
   *            String sessionid)
117
   */
118
  public void transformXMLDocument(String doc, String sourceType,
119
                String targetType, String qFormat, StringWriter pw)
120
  {
121
    transformXMLDocument(doc, sourceType, targetType, qFormat, pw, null);
122
  }
123

    
124

    
125
  /**
126
   * Transform an XML document using the stylesheet reference from the db
127
   *
128
   * @param doc the document to be transformed
129
   * @param sourcetype the document type of the source
130
   * @param targettype the target document type
131
   * @param qformat the name of the style set to use
132
   * @param pw the PrintWriter to which output is printed
133
   * @param params some parameters for eml2 transformation
134
   */
135
  public void transformXMLDocument(String doc, String sourceType,
136
                                   String targetType, String qformat,
137
                                   PrintWriter pw, Hashtable param,
138
                                   String sessionid)
139
 {
140

    
141
    // Look up the stylesheet for this type combination
142
    String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
143
    if (xslSystemId != null)
144
    {
145
      try
146
      {// Create a stylesheet from the system id that was found
147
        doc = removeDOCTYPE(doc);
148
        StringReader xml = new StringReader(doc);
149
        StreamResult result = new StreamResult(pw);
150
        doTransform(xml, result, xslSystemId, param, qformat, sessionid);
151

    
152
      }
153
      catch (Exception e)
154
      {
155
        pw.println(xslSystemId + "Error transforming document in " +
156
                   "DBTransform.transformXMLDocument: " +
157
                   e.getMessage());
158

    
159
      }
160
    }
161
    else
162
    {
163
      // No stylesheet registered form this document type, so just return the
164
      // XML stream we were passed
165
      pw.print(doc);
166
    }
167
  }
168

    
169
  /**
170
   * Transform an XML document to StringWriter using the stylesheet reference
171
   * from the db
172
   * @param doc the document to be transformed
173
   * @param sourceType the document type of the source
174
   * @param targetType the target document type
175
   * @param qFormat the name of the style set to use
176
   * @param pw the StringWriter to which output will be stored
177
   */
178
  public void transformXMLDocument(String doc, String sourceType,
179
                String targetType, String qFormat, StringWriter pw,
180
                String sessionid)
181
  {
182

    
183
    // Look up the stylesheet for this type combination
184
    String xslSystemId = getStyleSystemId(qFormat, sourceType, targetType);
185
    if (xslSystemId != null)
186
    {
187
      // Create a stylesheet from the system id that was found
188
      try
189
      {
190
        doc = removeDOCTYPE(doc);
191
        StringReader xml = new StringReader(doc);
192
        StreamResult result = new StreamResult(pw);
193
        doTransform(xml, result, xslSystemId, null, qFormat, sessionid);
194
      }
195
      catch (Exception e)
196
      {
197
        util.debugMessage(xslSystemId + "Error transforming document in " +
198
                   "DBTransform.transformXMLDocument: " +
199
                   e.getMessage(), 30);
200

    
201
      }
202
    }
203
    else
204
    {
205
      // No stylesheet registered form this document type, so just return the
206
      // XML stream we were passed
207
      pw.write(doc);
208
    }
209
  }
210

    
211
  /**
212
   * Method to do transform for a string reader
213
   * @param doc the document to be transformed
214
   * @param sourcetype the document type of the source
215
   * @param targettype the target document type
216
   * @param qformat the name of the style set to use
217
   * @param pw the PrintWriter to which output is printed
218
   * @param params some parameters for eml2 transformation
219
   */
220
   public void transformXMLDocument(StringReader docContent, String sourceType,
221
                                   String targetType, String qformat,
222
                                   PrintWriter pw, Hashtable param,
223
                                   String sessionid)
224
   {
225
     // Look up the stylesheet for this type combination
226
    String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
227
    if (xslSystemId != null)
228
    {
229
      try
230
      {// Create a stylesheet from the system id that was found
231
        StreamResult result = new StreamResult(pw);
232
        doTransform(docContent, result, xslSystemId, param, qformat, sessionid);
233

    
234
      }
235
      catch (Exception e)
236
      {
237
        pw.println(xslSystemId + "Error transforming document in " +
238
                   "DBTransform.transformXMLDocument: " +
239
                   e.getMessage());
240

    
241
      }
242
    }
243
    else
244
    {
245
      // No stylesheet registered form this document type, so just return the
246
      // XML stream we were passed
247
      pw.print(docContent);
248
    }
249
   }
250

    
251
  /*
252
   * Method to do transfer
253
   */
254
  private void doTransform(StringReader docContent, StreamResult resultOutput,
255
                           String xslSystemId, Hashtable param,
256
                           String qformat, String sessionid)
257
                          throws Exception
258
  {
259
    if (xslSystemId != null)
260
    {
261
        TransformerFactory tFactory = TransformerFactory.newInstance();
262
        Transformer transformer = tFactory.newTransformer(
263
                                  new StreamSource(xslSystemId));
264
        transformer.setParameter("qformat", qformat);
265
        MetaCatUtil.debugMessage("qformat: "+qformat, 30);
266

    
267
        if(sessionid != null)
268
        {
269
          transformer.setParameter("sessid", sessionid);
270
        }
271
        // Set up parameter for transformation
272
        if ( param != null)
273
        {
274
          Enumeration en = param.keys();
275
          while (en.hasMoreElements())
276
          {
277
            String key =(String)en.nextElement();
278
            String value = ((String[])(param.get(key)))[0];
279
            MetaCatUtil.debugMessage(key+" : "+value, 30);
280
            transformer.setParameter(key, value);
281
          }
282
        }
283
        StreamSource xml = new StreamSource(docContent);
284
        transformer.transform(xml,resultOutput);
285
    }
286
  }//doTransform
287

    
288

    
289
  /**
290
   * gets the content of a tag in a given xml file with the given path
291
   * @param f the file to parse
292
   * @param path the path to get the content from
293
   */
294
  public static NodeList getPathContent(File f, String path)
295
  {
296
    if(f == null)
297
    {
298
      return null;
299
    }
300

    
301
    DOMParser parser = new DOMParser();
302
    InputSource in;
303
    FileInputStream fs;
304

    
305
    try
306
    {
307
      fs = new FileInputStream(f);
308
      in = new InputSource(fs);
309
    }
310
    catch(FileNotFoundException fnf)
311
    {
312
      fnf.printStackTrace();
313
      return null;
314
    }
315

    
316
    try
317
    {
318
      parser.parse(in);
319
      fs.close();
320
    }
321
    catch(Exception e1)
322
    {
323
      System.err.println("File: " + f.getPath() + " : parse threw: " +
324
                         e1.toString());
325
      return null;
326
    }
327

    
328
    Document doc = parser.getDocument();
329

    
330
    try
331
    {
332
      NodeList docNodeList = XPathAPI.selectNodeList(doc, path);
333
      return docNodeList;
334
    }
335
    catch(Exception se)
336
    {
337
      System.err.println("file: " + f.getPath() + " : parse threw: " +
338
                         se.toString());
339
      return null;
340
    }
341
  }
342

    
343
  /**
344
   * Lookup a stylesheet reference from the db catalog
345
   *
346
   * @param qformat    the named style-set format
347
   * @param sourcetype the document type of the source
348
   * @param targettype the document type of the target
349
   */
350
  public String getStyleSystemId(String qformat, String sourcetype,
351
                String targettype) {
352
    String systemId = null;
353

    
354
    if ((qformat == null) || (qformat.equals("html"))) {
355
      qformat = defaultStyle;
356
    }
357

    
358
    // Load the style-set map for this qformat into a DOM
359
    try {
360
      boolean breakflag = false;
361
      String filename = configDir + "/" + qformat + "/" + qformat + ".xml";
362
      util.debugMessage("Trying style-set file: " + filename, 30);
363
      File f = new File(filename);
364
      NodeList nlDoctype = getPathContent(f, "/style-set/doctype");
365
      NodeList nlDefault = getPathContent(f, "/style-set/default-style");
366
      Node nDefault = nlDefault.item(0);
367
      systemId = nDefault.getFirstChild().getNodeValue(); //set the default
368

    
369
      for(int i=0; i<nlDoctype.getLength(); i++)
370
      { //look for the right sourcetype
371
        Node nDoctype = nlDoctype.item(i);
372
        NamedNodeMap atts = nDoctype.getAttributes();
373
        Node nAtt = atts.getNamedItem("publicid");
374
        String doctype = nAtt.getFirstChild().getNodeValue();
375
        if(doctype.equals(sourcetype))
376
        { //found the right sourcetype now we need to get the target type
377
          NodeList nlChildren = nDoctype.getChildNodes();
378
          for(int j=0; j<nlChildren.getLength(); j++)
379
          {
380
            Node nChild = nlChildren.item(j);
381
            String childName = nChild.getNodeName();
382
            if(childName.equals("target"))
383
            {
384
              NamedNodeMap childAtts = nChild.getAttributes();
385
              Node nTargetPublicId = childAtts.getNamedItem("publicid");
386
              String target = nTargetPublicId.getFirstChild().getNodeValue();
387
              if(target.equals(targettype))
388
              { //we found the right target type
389
                NodeList nlTarget = nChild.getChildNodes();
390
                for(int k=0; k<nlTarget.getLength(); k++)
391
                {
392
                  Node nChildText = nlTarget.item(k);
393
                  if(nChildText.getNodeType() == Node.TEXT_NODE)
394
                  { //get the text from the target node
395
                    systemId = nChildText.getNodeValue();
396
                    breakflag = true;
397
                    break;
398
                  }
399
                }
400
              }
401
            }
402

    
403
            if(breakflag)
404
            {
405
              break;
406
            }
407
          }
408
        }
409

    
410
        if(breakflag)
411
        {
412
          break;
413
        }
414
      }
415
    }
416
    catch(Exception e)
417
    {
418
      System.out.println("Error parsing style-set file: " + e.getMessage());
419
      e.printStackTrace();
420
    }
421

    
422
    // Return the system ID for this particular source document type
423
    MetaCatUtil.debugMessage("style system id is: "+systemId, 30);
424
    return systemId;
425
  }
426

    
427
 /* Method to modified the system id of xml input -- make sure it
428
    points to system id in xml_catalog table
429
  */
430
  private void modifiedXmlStreamSource(StreamSource xml, String publicId)
431
                                       throws Exception
432
  {
433
    // make sure the xml is not null
434
    if (xml == null || publicId == null)
435
    {
436
      return;
437
    }
438
    MetaCatUtil.debugMessage("public id of input stream is " +publicId, 25);
439
    // Get system id from xml_catalog table
440
    String systemId = DBEntityResolver.getDTDSystemID(publicId);
441
    MetaCatUtil.debugMessage("system id of input stream from xml_catalog"
442
                               +"table is " +systemId, 25);
443
    //set system id to input stream
444
    xml.setSystemId(systemId);
445
  }
446

    
447
  /*
448
   * removes the DOCTYPE element and its contents from a Sting
449
   * used to avoid problems with incorrect SystemIDs
450
   */
451
  private String removeDOCTYPE(String in) {
452
    String ret = "";
453
    int startpos = in.indexOf("<!DOCTYPE");
454
    if (startpos>-1) {
455
      int stoppos = in.indexOf(">", startpos + 8);
456
      ret = in.substring(0,startpos) + in.substring(stoppos+1,in.length());
457
    } else {
458
      return in;
459
    }
460
    return ret;
461
  }
462

    
463
  /**
464
   * the main routine used to test the transform utility.
465
   *
466
   * Usage: java DBTransform
467
   */
468
  static public void main(String[] args) {
469

    
470
     if (args.length > 0)
471
     {
472
        System.err.println("Wrong number of arguments!!!");
473
        System.err.println("USAGE: java DBTransform");
474
        return;
475
     } else {
476
        try {
477

    
478
          // Open a connection to the database
479
          /*MetaCatUtil   util = new MetaCatUtil();
480
          Connection dbconn = util.openDBConnection();*/
481

    
482
          // Create a test document
483
          StringBuffer testdoc = new StringBuffer();
484
          testdoc.append("<?xml version=\"1.0\"?>");
485
          testdoc.append("<eml-dataset><metafile_id>NCEAS-0001</metafile_id>");
486
          testdoc.append("<dataset_id>DS001</dataset_id>");
487
          testdoc.append("<title>My test doc</title></eml-dataset>");
488

    
489
          // Transform the document to the new doctype
490
          DBTransform dbt = new DBTransform();
491
          dbt.transformXMLDocument(testdoc.toString(),
492
                                   "-//NCEAS//eml-dataset//EN",
493
                                   "-//W3C//HTML//EN",
494
                                   "knb",
495
                                   new PrintWriter(System.out), null);
496

    
497
        } catch (Exception e) {
498
          System.err.println("EXCEPTION HANDLING REQUIRED");
499
          System.err.println(e.getMessage());
500
          e.printStackTrace(System.err);
501
        }
502
     }
503
  }
504

    
505
  private void dbg(int position) {
506
    System.err.println("Debug flag: " + position);
507
  }
508

    
509
}
(26-26/61)