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: daigle $'
10
 * '$Date: 2009-12-18 13:37:26 -0800 (Fri, 18 Dec 2009) $'
11
 * '$Revision: 5167 $'
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.sql.*;
32
import java.util.Enumeration;
33
import java.util.Hashtable;
34
import java.util.Iterator;
35
import java.util.Map;
36

    
37
import javax.xml.transform.TransformerFactory;
38
import javax.xml.transform.Transformer;
39
import javax.xml.transform.stream.StreamSource;
40
import javax.xml.transform.stream.StreamResult;
41

    
42
import org.apache.log4j.Logger;
43
import org.apache.xerces.parsers.DOMParser;
44
import org.w3c.dom.NamedNodeMap;
45
import org.w3c.dom.NodeList;
46
import org.w3c.dom.Document;
47
import org.w3c.dom.Node;
48
import org.xml.sax.InputSource;
49
import org.apache.xpath.XPathAPI;
50

    
51
import edu.ucsb.nceas.metacat.properties.PropertyService;
52
import edu.ucsb.nceas.metacat.properties.SkinPropertyService;
53
import edu.ucsb.nceas.metacat.util.SystemUtil;
54
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
55
import edu.ucsb.nceas.utilities.SortedProperties;
56

    
57
/**
58
 * A Class that transforms XML documents utitlizing XSL style sheets
59
 */
60
public class DBTransform {
61

    
62
  // private Connection	conn = null;
63
  // private MetacatUtil   util = null;
64
  private String 	configDir = null;
65
  private String	defaultStyle = null;
66
  private Logger logMetacat = Logger.getLogger(DBTransform.class);
67
  private String httpServer = null;
68
  private String contextURL = null;
69
  private String servletURL = null;
70
  
71
  /**
72
   * construct a DBTransform instance.
73
   *
74
   * Generally, one calls transformXMLDocument() after constructing the instance
75
   *
76
   * @param conn the database connection from which to lookup the public ids
77
   */
78
  public DBTransform()
79
                  throws IOException,
80
                         SQLException,
81
                         ClassNotFoundException,
82
                         PropertyNotFoundException
83
  {
84
    configDir = SystemUtil.getStyleSkinsDir();
85
    defaultStyle = PropertyService.getProperty("application.default-style");
86
    httpServer = SystemUtil.getServerURL();
87
    contextURL = SystemUtil.getContextURL();
88
    servletURL = SystemUtil.getServletURL();
89
  }
90

    
91
  /**
92
   * Transform an XML document using the stylesheet reference from the db
93
   *
94
   * @param doc the document to be transformed
95
   * @param sourcetype the document type of the source
96
   * @param targettype the target document type
97
   * @param qformat the name of the style set to use
98
   * @param pw the PrintWriter to which output is printed
99
   * @param params some parameters for eml2 transformation
100
   */
101
  public void transformXMLDocument(String doc, String sourceType,
102
                                   String targetType, String qformat,
103
                                   PrintWriter pw, Hashtable<String, String[]> param,
104
                                   String sessionid)
105
 {
106

    
107
    // Look up the stylesheet for this type combination
108
    String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
109
    if (xslSystemId != null)
110
    {
111
      try
112
      {// Create a stylesheet from the system id that was found
113
        doc = removeDOCTYPE(doc);
114
        StringReader xml = new StringReader(doc);
115
        StreamResult result = new StreamResult(pw);
116
        doTransform(xml, result, xslSystemId, param, qformat, sessionid);
117

    
118
      }
119
      catch (Exception e)
120
      {
121
        pw.println(xslSystemId + ": Error transforming document in " +
122
                   "DBTransform.transformXMLDocument: " +
123
                   e.getMessage());
124

    
125
      }
126
    }
127
    else
128
    {
129
      // No stylesheet registered form this document type, so just return the
130
      // XML stream we were passed
131
      pw.print(doc);
132
    }
133
  }
134
  
135
  /**
136
   * Transform an XML document to StringWriter using the stylesheet reference
137
   * from the db
138
   * @param doc the document to be transformed
139
   * @param sourceType the document type of the source
140
   * @param targetType the target document type
141
   * @param qFormat the name of the style set to use
142
   * @param pw the StringWriter to which output will be stored
143
   */
144
  public void transformXMLDocument(String doc, String sourceType,
145
                String targetType, String qFormat, StringWriter pw,
146
                Hashtable<String, String[]> param, String sessionid)
147
  {
148

    
149
    // Look up the stylesheet for this type combination
150
    String xslSystemId = getStyleSystemId(qFormat, sourceType, targetType);
151
    if (xslSystemId != null)
152
    {
153
      // Create a stylesheet from the system id that was found
154
      try
155
      {
156
        doc = removeDOCTYPE(doc);
157
        StringReader xml = new StringReader(doc);
158
        StreamResult result = new StreamResult(pw);
159
        doTransform(xml, result, xslSystemId, param, qFormat, sessionid);
160
      }
161
      catch (Exception e)
162
      {
163
        logMetacat.error("DBTransform.transformXMLDocument - " + xslSystemId + ": Error transforming document in " +
164
                   "DBTransform.transformXMLDocument: " +
165
                   e.getMessage());
166

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

    
177
  /**
178
   * Method to do transform for a string reader
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 PrintWriter to which output is printed
184
   * @param params some parameters for eml2 transformation
185
   */
186
   public void transformXMLDocument(StringReader docContent, String sourceType,
187
                                   String targetType, String qformat,
188
                                   PrintWriter pw, Hashtable<String, String[]> param,
189
                                   String sessionid)
190
   {
191
     // Look up the stylesheet for this type combination
192
    String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
193
    if (xslSystemId != null)
194
    {
195
      try
196
      {// Create a stylesheet from the system id that was found
197
        StreamResult result = new StreamResult(pw);
198
        doTransform(docContent, result, xslSystemId, param, qformat, sessionid);
199

    
200
      }
201
      catch (Exception e)
202
      {
203
        pw.println(xslSystemId + ": Error transforming document in " +
204
                   "DBTransform.transformXMLDocument: " +
205
                   e.getMessage());
206

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

    
217
  /**
218
   * Reads skin's config file if it exists, and populates Transformer paramaters
219
   * with its contents.
220
   * It then adds the parameters passed to it via Hashtable param to the Transformer.
221
   * It then calls the Transformer.transform method.
222
   */
223
  private void doTransform(StringReader docContent, 
224
          StreamResult resultOutput,
225
          String xslSystemId, 
226
          Hashtable<String, String[]> param,
227
          String qformat, 
228
          String sessionid) 
229
          throws Exception {
230
      
231
      SortedProperties skinOptions;
232
      TransformerFactory tFactory;
233
      Transformer transformer;
234
      String key, value;
235
      StreamSource xml;
236
      Enumeration<String> en;
237
      Iterator<Map.Entry<String, String>> iterIt;
238
      Map.Entry<String, String> entry;
239
      
240
      if (xslSystemId != null) {
241
        tFactory = TransformerFactory.newInstance();
242
        transformer = tFactory.newTransformer(new StreamSource(xslSystemId));
243
        
244
        transformer.setParameter("qformat", qformat);
245
        logMetacat.info("DBTransform.doTransform - qformat: " + qformat);
246
        
247
        skinOptions = SkinPropertyService.getProperties(qformat);
248
        if (skinOptions != null) {            
249
            iterIt = skinOptions.getProperties().entrySet().iterator();
250
            while (iterIt.hasNext()) {
251
                entry = iterIt.next();
252
                key = entry.getKey();
253
                value = entry.getValue();
254
                //only include the plain properties
255
                if (key.indexOf('.') == -1) {
256
                	transformer.setParameter(key, value);
257
                }
258
            }
259
        }
260
        
261
        if (sessionid != null && !sessionid.equals("null")) {
262
          transformer.setParameter("sessid", sessionid);
263
        }
264
        
265
        //set up the default params (can be overridden by the passed in params)
266
        String cgiPrefix = SystemUtil.getCGI_URL();
267
        logMetacat.debug("DBTransform.doTransform - cgi-prefix: " + cgiPrefix);
268
        logMetacat.debug("DBTransform.doTransform - httpServer: " + httpServer);
269
        logMetacat.debug("DBTransform.doTransform - contextURL: " + contextURL);
270
        logMetacat.debug("DBTransform.doTransform - serletURL: " + servletURL);
271
        transformer.setParameter("cgi-prefix", cgiPrefix);
272
        transformer.setParameter("httpServer", httpServer);
273
        transformer.setParameter("contextURL", contextURL);
274
        transformer.setParameter("servletURL", servletURL);
275
        
276
        // Set up parameter for transformation
277
        if ( param != null) {
278
          en = param.keys();
279
          while (en.hasMoreElements()) {
280
            key = en.nextElement();
281
            value = (param.get(key))[0];
282
            logMetacat.info("DBTransform.doTransform - param: " + key + " -- " + value);
283
            transformer.setParameter(key, value);
284
          }
285
        }
286
        xml = new StreamSource(docContent);
287
        transformer.transform(xml,resultOutput);
288
    }
289
  }//doTransform
290

    
291

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

    
304
    DOMParser parser = new DOMParser();
305
    InputSource in;
306
    FileInputStream fs;
307

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

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

    
331
    Document doc = parser.getDocument();
332

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

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

    
357
    if ((qformat == null) || (qformat.equals("html"))) {
358
      qformat = defaultStyle;
359
    }
360

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

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

    
406
            if(breakflag)
407
            {
408
              break;
409
            }
410
          }
411
        }
412

    
413
        if(breakflag)
414
        {
415
          break;
416
        }
417
      }
418
    }
419
    catch(Exception e)
420
    {
421
      System.out.println("Error parsing style-set file: " + e.getMessage());
422
      e.printStackTrace();
423
    }
424
    
425
    //Check if the systemId is relative path, add a postfix - the contextULR to systemID. 
426
    if (systemId != null && systemId.indexOf("http://" ) == -1)
427
    {
428
    	systemId = contextURL+systemId;
429
    }
430
    // Return the system ID for this particular source document type
431
    logMetacat.info("DBTransform.getStyleSystemId - style system id is: " + systemId);
432
    return systemId;
433
  }
434

    
435
// /* Method to modified the system id of xml input -- make sure it
436
//    points to system id in xml_catalog table
437
//  */
438
//  private void modifiedXmlStreamSource(StreamSource xml, String publicId)
439
//                                       throws Exception
440
//  {
441
//    // make sure the xml is not null
442
//    if (xml == null || publicId == null)
443
//    {
444
//      return;
445
//    }
446
//    logMetacat.info("public id of input stream is " +publicId);
447
//    // Get system id from xml_catalog table
448
//    String systemId = DBEntityResolver.getDTDSystemID(publicId);
449
//    logMetacat.info("system id of input stream from xml_catalog"
450
//                               +"table is " +systemId);
451
//    //set system id to input stream
452
//    xml.setSystemId(systemId);
453
//  }
454

    
455
  /*
456
   * removes the DOCTYPE element and its contents from a Sting
457
   * used to avoid problems with incorrect SystemIDs
458
   */
459
  private String removeDOCTYPE(String in) {
460
    String ret = "";
461
    int startpos = in.indexOf("<!DOCTYPE");
462
    if (startpos>-1) {
463
      int stoppos = in.indexOf(">", startpos + 8);
464
      ret = in.substring(0,startpos) + in.substring(stoppos+1,in.length());
465
    } else {
466
      return in;
467
    }
468
    return ret;
469
  }
470

    
471
  /**
472
   * the main routine used to test the transform utility.
473
   *
474
   * Usage: java DBTransform
475
   */
476
  static public void main(String[] args) {
477

    
478
     if (args.length > 0)
479
     {
480
        System.err.println("Wrong number of arguments!!!");
481
        System.err.println("USAGE: java DBTransform");
482
        return;
483
     } else {
484
        try {
485

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

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

    
501
        } catch (Exception e) {
502
          System.err.println("EXCEPTION HANDLING REQUIRED");
503
          System.err.println(e.getMessage());
504
          e.printStackTrace(System.err);
505
        }
506
     }
507
  }
508

    
509
//  private void dbg(int position) {
510
//    System.err.println("Debug flag: " + position);
511
//  }
512

    
513
}
(21-21/62)