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
 *
9
 * '$Author: barteau $'
10
 * '$Date: 2008-01-10 11:13:33 -0800 (Thu, 10 Jan 2008) $'
11
 * '$Revision: 3675 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.io.*;
31
import java.net.URL;
32
import java.net.MalformedURLException;
33
import java.sql.*;
34
import java.util.Enumeration;
35
import java.util.Hashtable;
36
import java.util.Iterator;
37
import java.util.Map;
38
import java.util.Map.Entry;
39
import java.util.Stack;
40

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

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

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

    
76
import java.util.Properties;
77

    
78

    
79
/**
80
 * A Class that transforms XML documents utitlizing XSL style sheets
81
 */
82
public class DBTransform {
83

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

    
108
  /**
109
   * @see transformXMLDocument(String doc, String sourceType,
110
   *            String targetType, String qformat, PrintWriter pw,
111
   *            String sessionid)
112
   */
113
  public void transformXMLDocument(String doc, String sourceType,
114
                String targetType, String qformat, PrintWriter pw,
115
                Hashtable param)
116
  {
117
    transformXMLDocument(doc, sourceType, targetType, qformat, pw, param, null);
118
  }
119

    
120
   /**
121
   * @see transformXMLDocument(String doc, String sourceType,
122
   *            String targetType, String qFormat, StringWriter pw
123
   *            String sessionid)
124
   */
125
  public void transformXMLDocument(String doc, String sourceType,
126
                String targetType, String qFormat, StringWriter pw)
127
  {
128
    transformXMLDocument(doc, sourceType, targetType, qFormat, pw, null);
129
  }
130

    
131

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

    
148
    // Look up the stylesheet for this type combination
149
    String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
150
    if (xslSystemId != null)
151
    {
152
      try
153
      {// Create a stylesheet from the system id that was found
154
        doc = removeDOCTYPE(doc);
155
        StringReader xml = new StringReader(doc);
156
        StreamResult result = new StreamResult(pw);
157
        doTransform(xml, result, xslSystemId, param, qformat, sessionid);
158

    
159
      }
160
      catch (Exception e)
161
      {
162
        pw.println(xslSystemId + "Error transforming document in " +
163
                   "DBTransform.transformXMLDocument: " +
164
                   e.getMessage());
165

    
166
      }
167
    }
168
    else
169
    {
170
      // No stylesheet registered form this document type, so just return the
171
      // XML stream we were passed
172
      pw.print(doc);
173
    }
174
  }
175

    
176
  /**
177
   * Transform an XML document to StringWriter using the stylesheet reference
178
   * from the db
179
   * @param doc the document to be transformed
180
   * @param sourceType the document type of the source
181
   * @param targetType the target document type
182
   * @param qFormat the name of the style set to use
183
   * @param pw the StringWriter to which output will be stored
184
   */
185
  public void transformXMLDocument(String doc, String sourceType,
186
                String targetType, String qFormat, StringWriter pw,
187
                String sessionid)
188
  {
189

    
190
    // Look up the stylesheet for this type combination
191
    String xslSystemId = getStyleSystemId(qFormat, sourceType, targetType);
192
    if (xslSystemId != null)
193
    {
194
      // Create a stylesheet from the system id that was found
195
      try
196
      {
197
        doc = removeDOCTYPE(doc);
198
        StringReader xml = new StringReader(doc);
199
        StreamResult result = new StreamResult(pw);
200
        doTransform(xml, result, xslSystemId, null, qFormat, sessionid);
201
      }
202
      catch (Exception e)
203
      {
204
        logMetacat.error(xslSystemId + "Error transforming document in " +
205
                   "DBTransform.transformXMLDocument: " +
206
                   e.getMessage());
207

    
208
      }
209
    }
210
    else
211
    {
212
      // No stylesheet registered form this document type, so just return the
213
      // XML stream we were passed
214
      pw.write(doc);
215
    }
216
  }
217

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

    
241
      }
242
      catch (Exception e)
243
      {
244
        pw.println(xslSystemId + "Error transforming document in " +
245
                   "DBTransform.transformXMLDocument: " +
246
                   e.getMessage());
247

    
248
      }
249
    }
250
    else
251
    {
252
      // No stylesheet registered form this document type, so just return the
253
      // XML stream we were passed
254
      pw.print(docContent);
255
    }
256
   }
257

    
258
  /**
259
   * Reads skin's config file if it exists, and populates Transformer paramaters
260
   * with its contents.
261
   * It then adds the parameters passed to it via Hashtable param to the Transformer.
262
   * It then calls the Transformer.transform method.
263
   */
264
  private void doTransform(StringReader docContent, 
265
          StreamResult resultOutput,
266
          String xslSystemId, 
267
          Hashtable param,
268
          String qformat, 
269
          String sessionid) 
270
          throws Exception {
271
      
272
      Properties skinOptions;
273
      TransformerFactory tFactory;
274
      Transformer transformer;
275
      String key, value;
276
      StreamSource xml;
277
      Enumeration en;
278
      Iterator iterIt;
279
      Map.Entry entry;
280
      
281
      if (xslSystemId != null) {
282
        tFactory = TransformerFactory.newInstance();
283
        transformer = tFactory.newTransformer(new StreamSource(xslSystemId));
284
        
285
        transformer.setParameter("qformat", qformat);
286
        logMetacat.warn("qformat: "+qformat);
287
        
288
        if (MetaCatUtil.hasSkinConfig(qformat)) {
289
            skinOptions = MetaCatUtil.getSkinConfig(qformat);
290
		
291
            iterIt = skinOptions.entrySet().iterator();
292
            while (iterIt.hasNext()) {
293
                entry = (Entry) iterIt.next();
294
                key = (String) entry.getKey();
295
                value = (String) entry.getValue();
296
                transformer.setParameter(key, value);
297
            }
298
        }
299
        
300
        if (sessionid != null && !sessionid.equals("null")) {
301
          transformer.setParameter("sessid", sessionid);
302
        }
303
        
304
        // Set up parameter for transformation
305
        if ( param != null) {
306
          en = param.keys();
307
          while (en.hasMoreElements()) {
308
            key = (String) en.nextElement();
309
            value = ((String[]) (param.get(key)))[0];
310
            logMetacat.info(key+" : "+value);
311
            transformer.setParameter(key, value);
312
          }
313
        }
314
        xml = new StreamSource(docContent);
315
        transformer.transform(xml,resultOutput);
316
    }
317
  }//doTransform
318

    
319

    
320
  /**
321
   * gets the content of a tag in a given xml file with the given path
322
   * @param f the file to parse
323
   * @param path the path to get the content from
324
   */
325
  public static NodeList getPathContent(File f, String path)
326
  {
327
    if(f == null)
328
    {
329
      return null;
330
    }
331

    
332
    DOMParser parser = new DOMParser();
333
    InputSource in;
334
    FileInputStream fs;
335

    
336
    try
337
    {
338
      fs = new FileInputStream(f);
339
      in = new InputSource(fs);
340
    }
341
    catch(FileNotFoundException fnf)
342
    {
343
      fnf.printStackTrace();
344
      return null;
345
    }
346

    
347
    try
348
    {
349
      parser.parse(in);
350
      fs.close();
351
    }
352
    catch(Exception e1)
353
    {
354
      System.err.println("File: " + f.getPath() + " : parse threw: " +
355
                         e1.toString());
356
      return null;
357
    }
358

    
359
    Document doc = parser.getDocument();
360

    
361
    try
362
    {
363
      NodeList docNodeList = XPathAPI.selectNodeList(doc, path);
364
      return docNodeList;
365
    }
366
    catch(Exception se)
367
    {
368
      System.err.println("file: " + f.getPath() + " : parse threw: " +
369
                         se.toString());
370
      return null;
371
    }
372
  }
373

    
374
  /**
375
   * Lookup a stylesheet reference from the db catalog
376
   *
377
   * @param qformat    the named style-set format
378
   * @param sourcetype the document type of the source
379
   * @param targettype the document type of the target
380
   */
381
  public String getStyleSystemId(String qformat, String sourcetype,
382
                String targettype) {
383
    String systemId = null;
384

    
385
    if ((qformat == null) || (qformat.equals("html"))) {
386
      qformat = defaultStyle;
387
    }
388

    
389
    // Load the style-set map for this qformat into a DOM
390
    try {
391
      boolean breakflag = false;
392
      String filename = configDir + "/" + qformat + "/" + qformat + ".xml";
393
      logMetacat.warn("Trying style-set file: " + filename);
394
      File f = new File(filename);
395
      NodeList nlDoctype = getPathContent(f, "/style-set/doctype");
396
      NodeList nlDefault = getPathContent(f, "/style-set/default-style");
397
      Node nDefault = nlDefault.item(0);
398
      systemId = nDefault.getFirstChild().getNodeValue(); //set the default
399

    
400
      for(int i=0; i<nlDoctype.getLength(); i++)
401
      { //look for the right sourcetype
402
        Node nDoctype = nlDoctype.item(i);
403
        NamedNodeMap atts = nDoctype.getAttributes();
404
        Node nAtt = atts.getNamedItem("publicid");
405
        String doctype = nAtt.getFirstChild().getNodeValue();
406
        if(doctype.equals(sourcetype))
407
        { //found the right sourcetype now we need to get the target type
408
          NodeList nlChildren = nDoctype.getChildNodes();
409
          for(int j=0; j<nlChildren.getLength(); j++)
410
          {
411
            Node nChild = nlChildren.item(j);
412
            String childName = nChild.getNodeName();
413
            if(childName.equals("target"))
414
            {
415
              NamedNodeMap childAtts = nChild.getAttributes();
416
              Node nTargetPublicId = childAtts.getNamedItem("publicid");
417
              String target = nTargetPublicId.getFirstChild().getNodeValue();
418
              if(target.equals(targettype))
419
              { //we found the right target type
420
                NodeList nlTarget = nChild.getChildNodes();
421
                for(int k=0; k<nlTarget.getLength(); k++)
422
                {
423
                  Node nChildText = nlTarget.item(k);
424
                  if(nChildText.getNodeType() == Node.TEXT_NODE)
425
                  { //get the text from the target node
426
                    systemId = nChildText.getNodeValue();
427
                    breakflag = true;
428
                    break;
429
                  }
430
                }
431
              }
432
            }
433

    
434
            if(breakflag)
435
            {
436
              break;
437
            }
438
          }
439
        }
440

    
441
        if(breakflag)
442
        {
443
          break;
444
        }
445
      }
446
    }
447
    catch(Exception e)
448
    {
449
      System.out.println("Error parsing style-set file: " + e.getMessage());
450
      e.printStackTrace();
451
    }
452

    
453
    // Return the system ID for this particular source document type
454
    logMetacat.info("style system id is: "+systemId);
455
    return systemId;
456
  }
457

    
458
 /* Method to modified the system id of xml input -- make sure it
459
    points to system id in xml_catalog table
460
  */
461
  private void modifiedXmlStreamSource(StreamSource xml, String publicId)
462
                                       throws Exception
463
  {
464
    // make sure the xml is not null
465
    if (xml == null || publicId == null)
466
    {
467
      return;
468
    }
469
    logMetacat.info("public id of input stream is " +publicId);
470
    // Get system id from xml_catalog table
471
    String systemId = DBEntityResolver.getDTDSystemID(publicId);
472
    logMetacat.info("system id of input stream from xml_catalog"
473
                               +"table is " +systemId);
474
    //set system id to input stream
475
    xml.setSystemId(systemId);
476
  }
477

    
478
  /*
479
   * removes the DOCTYPE element and its contents from a Sting
480
   * used to avoid problems with incorrect SystemIDs
481
   */
482
  private String removeDOCTYPE(String in) {
483
    String ret = "";
484
    int startpos = in.indexOf("<!DOCTYPE");
485
    if (startpos>-1) {
486
      int stoppos = in.indexOf(">", startpos + 8);
487
      ret = in.substring(0,startpos) + in.substring(stoppos+1,in.length());
488
    } else {
489
      return in;
490
    }
491
    return ret;
492
  }
493

    
494
  /**
495
   * the main routine used to test the transform utility.
496
   *
497
   * Usage: java DBTransform
498
   */
499
  static public void main(String[] args) {
500

    
501
     if (args.length > 0)
502
     {
503
        System.err.println("Wrong number of arguments!!!");
504
        System.err.println("USAGE: java DBTransform");
505
        return;
506
     } else {
507
        try {
508

    
509
          // Open a connection to the database
510
          /*MetaCatUtil   util = new MetaCatUtil();
511
          Connection dbconn = util.openDBConnection();*/
512

    
513
          // Create a test document
514
          StringBuffer testdoc = new StringBuffer();
515
          testdoc.append("<?xml version=\"1.0\"?>");
516
          testdoc.append("<eml-dataset><metafile_id>NCEAS-0001</metafile_id>");
517
          testdoc.append("<dataset_id>DS001</dataset_id>");
518
          testdoc.append("<title>My test doc</title></eml-dataset>");
519

    
520
          // Transform the document to the new doctype
521
          DBTransform dbt = new DBTransform();
522
          dbt.transformXMLDocument(testdoc.toString(),
523
                                   "-//NCEAS//eml-dataset//EN",
524
                                   "-//W3C//HTML//EN",
525
                                   "knb",
526
                                   new PrintWriter(System.out), null);
527

    
528
        } catch (Exception e) {
529
          System.err.println("EXCEPTION HANDLING REQUIRED");
530
          System.err.println(e.getMessage());
531
          e.printStackTrace(System.err);
532
        }
533
     }
534
  }
535

    
536
  private void dbg(int position) {
537
    System.err.println("Debug flag: " + position);
538
  }
539

    
540
}
(25-25/66)