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: 2003-11-18 11:08:10 -0800 (Tue, 18 Nov 2003) $'
12
 * '$Revision: 1903 $'
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
   * Transform an XML document using the stylesheet reference from the db
115
   *
116
   * @param doc the document to be transformed
117
   * @param sourcetype the document type of the source
118
   * @param targettype the target document type
119
   * @param qformat the name of the style set to use
120
   * @param pw the PrintWriter to which output is printed
121
   * @param params some parameters for eml2 transformation
122
   */
123
  public void transformXMLDocument(String doc, String sourceType,
124
                                   String targetType, String qformat,
125
                                   PrintWriter pw, Hashtable param,
126
                                   String sessionid)
127
 {
128

    
129
    // Look up the stylesheet for this type combination
130
    String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
131

    
132
    if (xslSystemId != null) {
133
      // Create a stylesheet from the system id that was found
134
      try {
135
        TransformerFactory tFactory = TransformerFactory.newInstance();
136
        Transformer transformer = tFactory.newTransformer(
137
                                  new StreamSource(xslSystemId));
138
        //transformer.setParameter("qformat", qformat);
139
        //MetaCatUtil.debugMessage("qformat: "+qformat, 30);
140

    
141
        if(sessionid != null)
142
        {
143
          transformer.setParameter("sessid", sessionid);
144
        }
145

    
146
        // Set up parameter for transformation
147
        if ( param != null)
148
        {
149
          Enumeration en = param.keys();
150
          while (en.hasMoreElements())
151
          {
152
            String key =(String)en.nextElement();
153
            String value = ((String[])(param.get(key)))[0];
154
            MetaCatUtil.debugMessage(key+" : "+value, 30);
155
            transformer.setParameter(key, value);
156
          }
157
        }
158
        
159
        doc = removeDOCTYPE(doc);
160
        StreamSource xml = new StreamSource(new StringReader(doc));
161
        //modify the system id for dtd
162
        //modifiedXmlStreamSource(xml, sourceType);
163
        transformer.transform(xml, new StreamResult(pw));
164
      } catch (Exception e) {
165
        pw.println(xslSystemId + "Error transforming document in " +
166
                   "DBTransform.transformXMLDocument: " +
167
                   e.getMessage());
168

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

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

    
190
    // Look up the stylesheet for this type combination
191
    String xslSystemId = getStyleSystemId(qFormat, sourceType, targetType);
192

    
193
    if (xslSystemId != null) {
194
      // Create a stylesheet from the system id that was found
195
      try {
196
        TransformerFactory tFactory = TransformerFactory.newInstance();
197
        Transformer transformer = tFactory.newTransformer(
198
                                  new StreamSource(xslSystemId));
199
        if(sessionid != null)
200
        {
201
          transformer.setParameter("sessid", sessionid);
202
        }
203
        transformer.setParameter("qFormat", qFormat);
204
        doc = removeDOCTYPE(doc);
205
        StreamSource xml = new StreamSource(new StringReader(doc));
206
        //modify the system id for dtd
207
        //modifiedXmlStreamSource(xml, sourceType);
208
        transformer.transform(xml, new StreamResult(pw));
209
      } catch (Exception e) {
210
        util.debugMessage(xslSystemId + "Error transforming document in " +
211
                   "DBTransform.transformXMLDocument: " +
212
                   e.getMessage(), 30);
213

    
214
      }
215
    } else {
216
      // No stylesheet registered form this document type, so just return the
217
      // XML stream we were passed
218
      pw.write(doc);
219
    }
220
  }
221

    
222
  /**
223
   * @see transformXMLDocument(String doc, String sourceType,
224
   *            String targetType, String qFormat, StringWriter pw
225
   *            String sessionid)
226
   */
227
  public void transformXMLDocument(String doc, String sourceType,
228
                String targetType, String qFormat, StringWriter pw)
229
  {
230
    transformXMLDocument(doc, sourceType, targetType, qFormat, pw, null);
231
  }
232

    
233
  /**
234
   * gets the content of a tag in a given xml file with the given path
235
   * @param f the file to parse
236
   * @param path the path to get the content from
237
   */
238
  public static NodeList getPathContent(File f, String path)
239
  {
240
    if(f == null)
241
    {
242
      return null;
243
    }
244

    
245
    DOMParser parser = new DOMParser();
246
    InputSource in;
247
    FileInputStream fs;
248

    
249
    try
250
    {
251
      fs = new FileInputStream(f);
252
      in = new InputSource(fs);
253
    }
254
    catch(FileNotFoundException fnf)
255
    {
256
      fnf.printStackTrace();
257
      return null;
258
    }
259

    
260
    try
261
    {
262
      parser.parse(in);
263
      fs.close();
264
    }
265
    catch(Exception e1)
266
    {
267
      System.err.println("File: " + f.getPath() + " : parse threw: " +
268
                         e1.toString());
269
      return null;
270
    }
271

    
272
    Document doc = parser.getDocument();
273

    
274
    try
275
    {
276
      NodeList docNodeList = XPathAPI.selectNodeList(doc, path);
277
      return docNodeList;
278
    }
279
    catch(Exception se)
280
    {
281
      System.err.println("file: " + f.getPath() + " : parse threw: " +
282
                         se.toString());
283
      return null;
284
    }
285
  }
286

    
287
  /**
288
   * Lookup a stylesheet reference from the db catalog
289
   *
290
   * @param qformat    the named style-set format
291
   * @param sourcetype the document type of the source
292
   * @param targettype the document type of the target
293
   */
294
  public String getStyleSystemId(String qformat, String sourcetype,
295
                String targettype) {
296
    String systemId = null;
297

    
298
    if ((qformat == null) || (qformat.equals("html"))) {
299
      qformat = defaultStyle;
300
    }
301

    
302
    // Load the style-set map for this qformat into a DOM
303
    try {
304
      boolean breakflag = false;
305
      String filename = configDir + "/" + qformat + ".xml";
306
      util.debugMessage("Trying style-set file: " + filename, 30);
307
      File f = new File(filename);
308
      NodeList nlDoctype = getPathContent(f, "/style-set/doctype");
309
      NodeList nlDefault = getPathContent(f, "/style-set/default-style");
310
      Node nDefault = nlDefault.item(0);
311
      systemId = nDefault.getFirstChild().getNodeValue(); //set the default
312

    
313
      for(int i=0; i<nlDoctype.getLength(); i++)
314
      { //look for the right sourcetype
315
        Node nDoctype = nlDoctype.item(i);
316
        NamedNodeMap atts = nDoctype.getAttributes();
317
        Node nAtt = atts.getNamedItem("publicid");
318
        String doctype = nAtt.getFirstChild().getNodeValue();
319
        if(doctype.equals(sourcetype))
320
        { //found the right sourcetype now we need to get the target type
321
          NodeList nlChildren = nDoctype.getChildNodes();
322
          for(int j=0; j<nlChildren.getLength(); j++)
323
          {
324
            Node nChild = nlChildren.item(j);
325
            String childName = nChild.getNodeName();
326
            if(childName.equals("target"))
327
            {
328
              NamedNodeMap childAtts = nChild.getAttributes();
329
              Node nTargetPublicId = childAtts.getNamedItem("publicid");
330
              String target = nTargetPublicId.getFirstChild().getNodeValue();
331
              if(target.equals(targettype))
332
              { //we found the right target type
333
                NodeList nlTarget = nChild.getChildNodes();
334
                for(int k=0; k<nlTarget.getLength(); k++)
335
                {
336
                  Node nChildText = nlTarget.item(k);
337
                  if(nChildText.getNodeType() == Node.TEXT_NODE)
338
                  { //get the text from the target node
339
                    systemId = nChildText.getNodeValue();
340
                    breakflag = true;
341
                    break;
342
                  }
343
                }
344
              }
345
            }
346

    
347
            if(breakflag)
348
            {
349
              break;
350
            }
351
          }
352
        }
353

    
354
        if(breakflag)
355
        {
356
          break;
357
        }
358
      }
359
    }
360
    catch(Exception e)
361
    {
362
      System.out.println("Error parsing style-set file: " + e.getMessage());
363
      e.printStackTrace();
364
    }
365

    
366
    // Return the system ID for this particular source document type
367
    MetaCatUtil.debugMessage("style system id is: "+systemId, 30);
368
    return systemId;
369
  }
370

    
371
 /* Method to modified the system id of xml input -- make sure it
372
    points to system id in xml_catalog table
373
  */
374
  private void modifiedXmlStreamSource(StreamSource xml, String publicId)   
375
                                       throws Exception
376
  {
377
    // make sure the xml is not null
378
    if (xml == null || publicId == null)
379
    {
380
      return;
381
    }
382
    MetaCatUtil.debugMessage("public id of input stream is " +publicId, 25);
383
    // Get system id from xml_catalog table
384
    String systemId = DBEntityResolver.getDTDSystemID(publicId);
385
    MetaCatUtil.debugMessage("system id of input stream from xml_catalog"
386
                               +"table is " +systemId, 25);
387
    //set system id to input stream
388
    xml.setSystemId(systemId);
389
  }
390
  
391
  /*
392
   * removes the DOCTYPE element and its contents from a Sting
393
   * used to avoid problems with incorrect SystemIDs 
394
   */
395
  private String removeDOCTYPE(String in) {  
396
    String ret = "";
397
    int startpos = in.indexOf("<!DOCTYPE");
398
    if (startpos>-1) {
399
      int stoppos = in.indexOf(">", startpos + 8);   
400
      ret = in.substring(0,startpos) + in.substring(stoppos+1,in.length());
401
    } else {
402
      return in;
403
    }
404
    return ret;  
405
  }
406

    
407
  /**
408
   * the main routine used to test the transform utility.
409
   *
410
   * Usage: java DBTransform
411
   */
412
  static public void main(String[] args) {
413

    
414
     if (args.length > 0)
415
     {
416
        System.err.println("Wrong number of arguments!!!");
417
        System.err.println("USAGE: java DBTransform");
418
        return;
419
     } else {
420
        try {
421

    
422
          // Open a connection to the database
423
          /*MetaCatUtil   util = new MetaCatUtil();
424
          Connection dbconn = util.openDBConnection();*/
425

    
426
          // Create a test document
427
          StringBuffer testdoc = new StringBuffer();
428
          testdoc.append("<?xml version=\"1.0\"?>");
429
          testdoc.append("<eml-dataset><metafile_id>NCEAS-0001</metafile_id>");
430
          testdoc.append("<dataset_id>DS001</dataset_id>");
431
          testdoc.append("<title>My test doc</title></eml-dataset>");
432

    
433
          // Transform the document to the new doctype
434
          DBTransform dbt = new DBTransform();
435
          dbt.transformXMLDocument(testdoc.toString(),
436
                                   "-//NCEAS//eml-dataset//EN",
437
                                   "-//W3C//HTML//EN",
438
                                   "knb",
439
                                   new PrintWriter(System.out), null);
440

    
441
        } catch (Exception e) {
442
          System.err.println("EXCEPTION HANDLING REQUIRED");
443
          System.err.println(e.getMessage());
444
          e.printStackTrace(System.err);
445
        }
446
     }
447
  }
448

    
449
  private void dbg(int position) {
450
    System.err.println("Debug flag: " + position);
451
  }
452

    
453
}
(26-26/58)