You are viewing a plain text version of this content. The canonical link for it is here.
Posted to j-users@xalan.apache.org by Pramodh Peddi <pe...@contextmedia.com> on 2003/12/17 17:28:38 UTC

resolving DTDs while transforming

Hi,
I posted a requestion and I did not get any response back. I thought it was
difficult to understand what I asked in my previous post.
Here is a better way of explaining my question(s):
I have an xml source, to be transformed, which has a relative DTD reference
(just the dtd filename is specified), like:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE CONTENT_FEED SYSTEM "myDTD.dtd">
<root>
......
....
</root>

The problem is myDTD.dtd is available NEITHER in the classpath NOR where the
class file is located. But, it is available in a http-accessible location,
like: http://myserver.com/dtd/myDTD.dtd.

So, I would like to tell the parser to consider
"http://myserver.com/dtd/myDTD.dtd" instead of myDTD.dtd to validate the
source xml. (I know thats a stupid way of referring to a DTD, but thats the
customer's feed and they cannot change it).

I know this may not be related to transformation, but was wondering if you
kindly can help me.

Can any one help me get an approach.

Here is what I am doing: I am using Java1.4 API to transform. I am using
SAXSource to provide the xml source to the transformer. I am using
EntityResolver interface to resolve the DTD (to let the parser consider the
http://myserver.com/dtd/myDTD.dtd in place of myDTD.dtd, mentioned in the
source xml). I just have an idea how to do, but it does not work and no
wonder because I do not yet clearly understand how EntityResolver works.
Questions Like: What is the role of systemID, publicID, when does the parser
try to resolve entities (like DTDs), etc. Can anyone give a clear
understanding of how it works.

I hesitate giving the code, because the email becomes too large and
incognizable. But, in case it helps you help me better, here is the code:

*********************************************code***************************
************
public class SELTransformationService{

private String stylesheet;
private String fileName = null;
private String dtdURL = null;

private void transform(String metadata, String stylesheet,
ServiceRequest req, ServiceResponse res){

//System.out.println("TRANSFORM USING STRING");

try {

TransformerFactory tFactory = TransformerFactory.newInstance();

Transformer transformer = tFactory.newTransformer(new StreamSource(new
URL(stylesheet).openStream()));

InputStream inputStream =
req.getContentObject().getMetadataInputStream();

OutputStream outputStream =
req.getContentObject().getMetadataOutputStream();

SAXParserFactory pfactory= SAXParserFactory.newInstance();

pfactory.setValidating(true);

// Get an XMLReader.

XMLReader reader = pfactory.newSAXParser().getXMLReader();

//create a resolver to resolve the DTD in the source xml

//EntityResolver resolver = new DTDResolver();

reader.setEntityResolver(new DTDResolver());

DTDResolver resolver = (DTDResolver)reader.getEntityResolver();

resolver.setPublicId(this.dtdURL);

SAXSource source = new SAXSource(reader,

new InputSource(new InputStreamReader(inputStream)));

source.setSystemId("myDTD.dtd");

transformer.transform(source, new StreamResult(new
OutputStreamWriter(outputStream, "iso-8859-1")));

outputStream.close();

req.getContentObject().commit();

res.send(req.getContentObject());

log.info(fileName + " - OBJECT SENT OUT OF TRANSFORMATION-2");

} catch (Exception ex) {

res.error(req.getContentObject(), "Exception sending message to bus.");

ex.printStackTrace();

}

}//end SELTransformationService classclass DTDResolver implements
EntityResolver {

String publicId = null;

public void setPublicId(String publicId){

this.publicId = publicId;

System.out.println("Setting publicID");

}

public String getPublicId(){

System.out.println("Getting publicId");

return this.publicId;

}

public InputSource resolveEntity (String publicId, String systemId){

InputStream inputStream = null;

InputSource source = null;

try{

System.out.println("publicID is: " + this.publicId);

if(StringUtils.isNotEmpty(this.publicId)){

URL url = new URL(this.publicId);

inputStream = url.openStream();

System.out.println("got the inputstream");

source = new InputSource(new InputStreamReader(inputStream));

}else{

System.out.println("publicId is not specified!!!");

}

}catch(Exception e){

}

return source;

}

}//end DTDResolver class
**********************************************code**************************
**************

When I do what is given above, the transformed string has empty xml (has
only xml header). I am sure I am doing something wrong. Can any one tell me
what is wrong in that. And making me understand how EntityResolver works
makes me feel lot better.

Thanks,

Pramodh.


Re: resolving DTDs while transforming

Posted by Bhakti Mehta <Bh...@Sun.COM>.
Pramod,
I had read this article some time ago. Check this out, I think it may help .
http://wwws.sun.com/software/xml/developers/resolver/article/

Regards,
Bhakti

Pramodh Peddi wrote:

>Hi,
>I posted a requestion and I did not get any response back. I thought it was
>difficult to understand what I asked in my previous post.
>Here is a better way of explaining my question(s):
>I have an xml source, to be transformed, which has a relative DTD reference
>(just the dtd filename is specified), like:
><?xml version="1.0" encoding="iso-8859-1"?>
><!DOCTYPE CONTENT_FEED SYSTEM "myDTD.dtd">
><root>
>......
>....
></root>
>
>The problem is myDTD.dtd is available NEITHER in the classpath NOR where the
>class file is located. But, it is available in a http-accessible location,
>like: http://myserver.com/dtd/myDTD.dtd.
>
>So, I would like to tell the parser to consider
>"http://myserver.com/dtd/myDTD.dtd" instead of myDTD.dtd to validate the
>source xml. (I know thats a stupid way of referring to a DTD, but thats the
>customer's feed and they cannot change it).
>
>I know this may not be related to transformation, but was wondering if you
>kindly can help me.
>
>Can any one help me get an approach.
>
>Here is what I am doing: I am using Java1.4 API to transform. I am using
>SAXSource to provide the xml source to the transformer. I am using
>EntityResolver interface to resolve the DTD (to let the parser consider the
>http://myserver.com/dtd/myDTD.dtd in place of myDTD.dtd, mentioned in the
>source xml). I just have an idea how to do, but it does not work and no
>wonder because I do not yet clearly understand how EntityResolver works.
>Questions Like: What is the role of systemID, publicID, when does the parser
>try to resolve entities (like DTDs), etc. Can anyone give a clear
>understanding of how it works.
>
>I hesitate giving the code, because the email becomes too large and
>incognizable. But, in case it helps you help me better, here is the code:
>
>*********************************************code***************************
>************
>public class SELTransformationService{
>
>private String stylesheet;
>private String fileName = null;
>private String dtdURL = null;
>
>private void transform(String metadata, String stylesheet,
>ServiceRequest req, ServiceResponse res){
>
>//System.out.println("TRANSFORM USING STRING");
>
>try {
>
>TransformerFactory tFactory = TransformerFactory.newInstance();
>
>Transformer transformer = tFactory.newTransformer(new StreamSource(new
>URL(stylesheet).openStream()));
>
>InputStream inputStream =
>req.getContentObject().getMetadataInputStream();
>
>OutputStream outputStream =
>req.getContentObject().getMetadataOutputStream();
>
>SAXParserFactory pfactory= SAXParserFactory.newInstance();
>
>pfactory.setValidating(true);
>
>// Get an XMLReader.
>
>XMLReader reader = pfactory.newSAXParser().getXMLReader();
>
>//create a resolver to resolve the DTD in the source xml
>
>//EntityResolver resolver = new DTDResolver();
>
>reader.setEntityResolver(new DTDResolver());
>
>DTDResolver resolver = (DTDResolver)reader.getEntityResolver();
>
>resolver.setPublicId(this.dtdURL);
>
>SAXSource source = new SAXSource(reader,
>
>new InputSource(new InputStreamReader(inputStream)));
>
>source.setSystemId("myDTD.dtd");
>
>transformer.transform(source, new StreamResult(new
>OutputStreamWriter(outputStream, "iso-8859-1")));
>
>outputStream.close();
>
>req.getContentObject().commit();
>
>res.send(req.getContentObject());
>
>log.info(fileName + " - OBJECT SENT OUT OF TRANSFORMATION-2");
>
>} catch (Exception ex) {
>
>res.error(req.getContentObject(), "Exception sending message to bus.");
>
>ex.printStackTrace();
>
>}
>
>}//end SELTransformationService classclass DTDResolver implements
>EntityResolver {
>
>String publicId = null;
>
>public void setPublicId(String publicId){
>
>this.publicId = publicId;
>
>System.out.println("Setting publicID");
>
>}
>
>public String getPublicId(){
>
>System.out.println("Getting publicId");
>
>return this.publicId;
>
>}
>
>public InputSource resolveEntity (String publicId, String systemId){
>
>InputStream inputStream = null;
>
>InputSource source = null;
>
>try{
>
>System.out.println("publicID is: " + this.publicId);
>
>if(StringUtils.isNotEmpty(this.publicId)){
>
>URL url = new URL(this.publicId);
>
>inputStream = url.openStream();
>
>System.out.println("got the inputstream");
>
>source = new InputSource(new InputStreamReader(inputStream));
>
>}else{
>
>System.out.println("publicId is not specified!!!");
>
>}
>
>}catch(Exception e){
>
>}
>
>return source;
>
>}
>
>}//end DTDResolver class
>**********************************************code**************************
>**************
>
>When I do what is given above, the transformed string has empty xml (has
>only xml header). I am sure I am doing something wrong. Can any one tell me
>what is wrong in that. And making me understand how EntityResolver works
>makes me feel lot better.
>
>Thanks,
>
>Pramodh.
>
>  
>



Re: resolving DTDs while transforming

Posted by Pramodh Peddi <pe...@contextmedia.com>.
Richard, Thanx for the quick reply. I am doing almost similar to what the
xalan site says. But, I have some more information this time.
The application is running on JBoss Appserver. As you know, the source xml
has DTD reference called "myDTD.dtd". The application is throwing an error
saying it is looking for the SystemID "file:///C:/jboss/bin/myDTD.dtd".

And when i say:
public InputSource resolveEntity (String publicId, String systemId)
    {
      if (systemId.equals("myDTD.dtd")) {
               // return a special input source
             return (new URL("http://myserver.com/dtd/myDTD.dtd"
 )).openStream();
      } else {
               // use the default behaviour
System.out.println("DOES NOT MATCH THE DTD STRING");
        return null;
      }
    }

it is printing "DOES NOT MATCH THE DTD STRING", because it is looking for
the systemId "file:///C:/jboss/bin/myDTD.dtd". And earlier, i did not put
any "if" stmt and was sending the inputSource of
"http://myserver.com/dtd/myDTD.dtd" no matter what. In this case, it was not
throwing an error, but was giving empty string out of the transformation
(the transformed string just had the xml header, and with wrong encoding).

For extra information, i am setting the systemId to "myDTD.dtd" explicitly
by calling source.setSystemId("myDTD.dtd"); where source is instance of
SAXSource.

I really do not know whats happening.

Hope I'll find some help to fix this problem.

Pramodh.

----- Original Message ----- 
From: "Richard Cao" <ri...@ca.ibm.com>
To: "Pramodh Peddi" <pe...@contextmedia.com>
Cc: <xa...@xml.apache.org>
Sent: Wednesday, December 17, 2003 12:01 PM
Subject: Re: resolving DTDs while transforming


>
>
>
>
> "Pramodh Peddi" <pe...@contextmedia.com> wrote on 12/17/2003 11:28:38 AM:
>
> > Hi,
> > I posted a requestion and I did not get any response back. I thought it
> was
> > difficult to understand what I asked in my previous post.
> > Here is a better way of explaining my question(s):
> > I have an xml source, to be transformed, which has a relative DTD
> reference
> > (just the dtd filename is specified), like:
> > <?xml version="1.0" encoding="iso-8859-1"?>
> > <!DOCTYPE CONTENT_FEED SYSTEM "myDTD.dtd">
> > <root>
> > ......
> > ....
> > </root>
> >
> > The problem is myDTD.dtd is available NEITHER in the classpath NOR where
> the
> > class file is located. But, it is available in a http-accessible
> location,
> > like: http://myserver.com/dtd/myDTD.dtd.
> >
> > So, I would like to tell the parser to consider
> > "http://myserver.com/dtd/myDTD.dtd" instead of myDTD.dtd to validate the
> > source xml. (I know thats a stupid way of referring to a DTD, but thats
> the
> > customer's feed and they cannot change it).
>
> http://xml.apache.org/xalan-j/apidocs/org/xml/sax/EntityResolver.html has
> an example similar to what you want to do.
>
> In the class that implements EntityResolver (your DTDResolver), you want
> the method
>
>    public InputSource resolveEntity (String publicId, String systemId)
>    {
>      if (systemId.equals("myDTD.dtd")) {
>               // return a special input source
>             return (new URL("http://myserver.com/dtd/myDTD.dtd"
> )).openStream();
>      } else {
>               // use the default behaviour
>        return null;
>      }
>    }
>
>


Re: resolving DTDs while transforming

Posted by Richard Cao <ri...@ca.ibm.com>.



"Pramodh Peddi" <pe...@contextmedia.com> wrote on 12/17/2003 11:28:38 AM:

> Hi,
> I posted a requestion and I did not get any response back. I thought it
was
> difficult to understand what I asked in my previous post.
> Here is a better way of explaining my question(s):
> I have an xml source, to be transformed, which has a relative DTD
reference
> (just the dtd filename is specified), like:
> <?xml version="1.0" encoding="iso-8859-1"?>
> <!DOCTYPE CONTENT_FEED SYSTEM "myDTD.dtd">
> <root>
> ......
> ....
> </root>
>
> The problem is myDTD.dtd is available NEITHER in the classpath NOR where
the
> class file is located. But, it is available in a http-accessible
location,
> like: http://myserver.com/dtd/myDTD.dtd.
>
> So, I would like to tell the parser to consider
> "http://myserver.com/dtd/myDTD.dtd" instead of myDTD.dtd to validate the
> source xml. (I know thats a stupid way of referring to a DTD, but thats
the
> customer's feed and they cannot change it).

http://xml.apache.org/xalan-j/apidocs/org/xml/sax/EntityResolver.html has
an example similar to what you want to do.

In the class that implements EntityResolver (your DTDResolver), you want
the method

   public InputSource resolveEntity (String publicId, String systemId)
   {
     if (systemId.equals("myDTD.dtd")) {
              // return a special input source
            return (new URL("http://myserver.com/dtd/myDTD.dtd"
)).openStream();
     } else {
              // use the default behaviour
       return null;
     }
   }


Re: resolving DTDs while transforming

Posted by Pramodh Peddi <pe...@contextmedia.com>.
Hi Gary, Richard, and All,

I am happy to let you know that I got the DTD thing working perfectly. Lot
of Thanks to all trying to help me on this problem. I had to add the
following stmt to get the basic validation working:
pfactory.setNamespaceAware(true).
Now, I even implemented the ErrorHandler to handle the Exceptions coming
from DTD validation.

But, still a couple of mysteries haunt me:
1. What is the purpose of the call source.setSystemId("myDTD11.dtd") ? Any
String in place of myDTD11.dtd works. The dtd in the xml source is
myDTD.dtd. So, I din't understand its significance.

2. I din't understand why I am using
reader.setFeature("http://xml.org/sax/features/validation", true). I just
know it din't work when I din't use it. We are anyhow using
pfactory.setValidating(true). And what else is the setFeature method used
for?

I am providing the code, hoping it would be helpful to anyone working on a
smililar thing.

************************code********************
   TransformerFactory tFactory = TransformerFactory.newInstance();

   Transformer transformer = tFactory.newTransformer(new StreamSource(new
URL(this.stylesheet).openStream()));

    InputStream inputStream = getInputStream();

   //create the factory
   SAXParserFactory pfactory= SAXParserFactory.newInstance();
   pfactory.setNamespaceAware(true);

    pfactory.setValidating(true);


   // Get an XMLReader.
   XMLReader reader = pfactory.newSAXParser().getXMLReader();
   log.debug("validating is: " + pfactory.isValidating());

   //create a resolver to resolve the DTD in the source xml ONLY if
   //you want to validate it against the given DTD

    reader.setEntityResolver(new DTDResolver());
    //  Turn Validation on
    try {
     reader.setFeature("http://xml.org/sax/features/validation",
         true);
    } catch (SAXNotRecognizedException e) {
     log.error(e);
    } catch (SAXNotSupportedException e) {
     log.error(e);
    }
    reader.setErrorHandler(new DTDErrorHandler());

    DTDResolver resolver = (DTDResolver)reader.getEntityResolver();
    //send the location of the DTD to the resolver
    resolver.setDtdLocation(this.dtdURL);

   SAXSource source = new SAXSource(reader,
     new InputSource(new InputStreamReader(inputStream, "iso-8859-1")));
   //TODO - look at this
   source.setSystemId("myDTD11.dtd");

   transformer.transform(source, new StreamResult(new
OutputStreamWriter(outputStream, "iso-8859-1")));
   log.info("out of transform");
   outputStream.close();
************************************************

Thanks again!!

Pramodh.

----- Original Message ----- 
From: "Pramodh Peddi" <pe...@contextmedia.com>
To: "Gary L Peskin" <ga...@firstech.com>; <xa...@xml.apache.org>
Sent: Wednesday, December 17, 2003 3:27 PM
Subject: Re: resolving DTDs while transforming


> Thanx for the response Gary.
>
> Sorry for the confusion on publicId thing. Though, I think it is right, it
> is very confusing. I fixed that.
>
> Reg'g the set and get methods in the DTDResolver class: I have to pass the
> dtd's URL (to be used as dtd) to the DTDResolver class, so that it can
> return the InputSource of that url. Thats the reason it has a get and a
set
> method for dtdLocation. I cleaned the class and used this code3, which
> doesn't work either. It still generates an empty string after transforming
> the source (as I said, its not exactly empty, it has just xml header in
> it...that too not with the intended encoding). This is my DTDesolver I am
> using right now. It is invoking the resolveEntity method of the
DTDResovler
> class.
>
> ***********************DTDResolver*******************
>  class DTDResolver implements EntityResolver {
>   String dtdLocation = null;
>
>   public void setDtdLocation(String string){
>    this.dtdLocation = string;
>    System.out.println("Setting dtdURL: " + this.dtdLocation);
>   }
>
>   public String getDtdLocation(){
>    System.out.println("Getting publicId");
>    return this.dtdLocation;
>   }
>
>   public InputSource resolveEntity (String publicId, String systemId){
>     InputStream inputStream = null;
>     InputSource source = null;
>     try{
>        System.out.println("systemId: " + systemId);
>      System.out.println("publicId: " + publicId);
>      System.out.println("dtdLocation is: " + this.dtdLocation);
>      if(StringUtils.isNotEmpty(this.dtdLocation)){
>
>      URL url = new URL(this.dtdLocation);
>
>      inputStream = url.openStream();
>      System.out.println("got the inputstream");
>      source = new InputSource(inputStream);
>      }else{
>     System.out.println("publicId is not specified!!!");
>      }
>     }catch(Exception e){
>        e.printStackTrace();
>   }
>
>   return source;
>
>    }
>  }//end DTDResolver
> *****************************************
>
> And this is the output I am getting:
>
> --------------------------------output-------------------------------
> 15:02:55,328 INFO  [STDOUT] Setting dtdLocation:
> http://localhost:8080/data/SonyDAMAs
> setMetadata.dtd
> 15:02:55,328 INFO  [STDOUT] systemId:
> file:///C:/jboss-3.0.6/bin/SonyDAMAssetMet
> adata.dtd
> 15:02:55,328 INFO  [STDOUT] publicId: null
> 15:02:55,328 INFO  [STDOUT] dtdLocation is:
> http://localhost:8080/data/SonyDAMAs
> setMetadata.dtd
> 15:02:55,343 INFO  [STDOUT] got the inputstream
> -----------------------------output---------------------------------------
-
>
> FYI: The application is running on JBoss appserver.
>
> As I said, in my previous reponse to Richard, the server is running in
> jboss/bin directory and so the systemId is being set to
> file:///C:/jboss-3.0.6/bin/SonyDAMAssetMetadata.dtd. And I am not sure how
> will the publicId be set! Will it ever be set and/or used? This is what
> makes me so uncomfortable with EntityResolver.
>
> FYI: This is the transformation code:
>
> ####################################Transformation
> code###########################
>    TransformerFactory tFactory = TransformerFactory.newInstance();
>
>    Transformer transformer = tFactory.newTransformer(new StreamSource(new
> URL(stylesheet).openStream()));
>
>    InputStream inputStream =
> req.getContentObject().getMetadataInputStream();
>    OutputStream outputStream =
> req.getContentObject().getMetadataOutputStream();
>
>    SAXParserFactory pfactory= SAXParserFactory.newInstance();
>    pfactory.setValidating(true);
>    // Get an XMLReader.
>    XMLReader reader = pfactory.newSAXParser().getXMLReader();
>
>    //create a resolver to resolve the DTD in the source xml
>    reader.setEntityResolver(new DTDResolver());
>    DTDResolver resolver = (DTDResolver)reader.getEntityResolver();
>    resolver.setDtdLocation(this.dtdURL);
>
>    SAXSource source = new SAXSource(reader,
>      new InputSource(new InputStreamReader(inputStream)));
> //not sure if this is right!
> //if i don't have this, it throws an exception saying it cannot find
> "SonyDAMAssetMetadata.dtd"
>    source.setSystemId("SonyDAMAssetMetadata.dtd");
>
>    transformer.transform(source, new StreamResult(new
> OutputStreamWriter(outputStream, "iso-8859-1")));
>
############################################################################
> #################
>
> Hope you found more info about my problem to help me better:-)!
>
> Thanks,
>
> Pramodh.
>
>


RE: resolving DTDs while transforming

Posted by Gary L Peskin <ga...@firstech.com>.
>From your output, it looks like your EntityResolver is being called and all
of that is fine.  The publicID would be supplied by the parser if your
!DOCTYPE declaration used the PUBLIC form of the externalID.  However, your
document uses the SYSTEM form and that is exactly what is being passed.

So, I think your DTDResolver is basically fine.  You have some cleanup to
do.  Your "if" statement checks this.dtdLocation but your message reports on
publicID.  But it is basically fine.

This brings us to your transformation itself.

I don't understand what you're doing with the source.setSystemId() call.  It
sounds like you're saying that the source and DTD both have the same name.
Try changing the name on the setSystemId() call and see if the error message
still refers to SonyDAMAssetMetadata.dtd.  If so, it means that the parser
just can't find your DTD.

Also try changing the URL you're passing into setDTDLocation and see how
this affects your error messages.

Have you tried the transformation from the command line to make sure it
works at all?

Gary

> -----Original Message-----
> From: Pramodh Peddi [mailto:peddip@contextmedia.com] 
> Sent: Wednesday, December 17, 2003 12:28 PM
> To: Gary L Peskin; xalan-j-users@xml.apache.org
> Subject: Re: resolving DTDs while transforming
> 
> 
> Thanx for the response Gary.
> 
> Sorry for the confusion on publicId thing. Though, I think it 
> is right, it is very confusing. I fixed that.
> 
> Reg'g the set and get methods in the DTDResolver class: I 
> have to pass the dtd's URL (to be used as dtd) to the 
> DTDResolver class, so that it can return the InputSource of 
> that url. Thats the reason it has a get and a set method for 
> dtdLocation. I cleaned the class and used this code3, which 
> doesn't work either. It still generates an empty string after 
> transforming the source (as I said, its not exactly empty, it 
> has just xml header in it...that too not with the intended 
> encoding). This is my DTDesolver I am using right now. It is 
> invoking the resolveEntity method of the DTDResovler class.
> 
> ***********************DTDResolver*******************
>  class DTDResolver implements EntityResolver {
>   String dtdLocation = null;
> 
>   public void setDtdLocation(String string){
>    this.dtdLocation = string;
>    System.out.println("Setting dtdURL: " + this.dtdLocation);
>   }
> 
>   public String getDtdLocation(){
>    System.out.println("Getting publicId");
>    return this.dtdLocation;
>   }
> 
>   public InputSource resolveEntity (String publicId, String systemId){
>     InputStream inputStream = null;
>     InputSource source = null;
>     try{
>        System.out.println("systemId: " + systemId);
>      System.out.println("publicId: " + publicId);
>      System.out.println("dtdLocation is: " + this.dtdLocation);
>      if(StringUtils.isNotEmpty(this.dtdLocation)){
> 
>      URL url = new URL(this.dtdLocation);
> 
>      inputStream = url.openStream();
>      System.out.println("got the inputstream");
>      source = new InputSource(inputStream);
>      }else{
>     System.out.println("publicId is not specified!!!");
>      }
>     }catch(Exception e){
>        e.printStackTrace();
>   }
> 
>   return source;
> 
>    }
>  }//end DTDResolver
> *****************************************
> 
> And this is the output I am getting:
> 
> --------------------------------output-------------------------------
> 15:02:55,328 INFO  [STDOUT] Setting dtdLocation: 
> http://localhost:8080/data/SonyDAMAs
> setMetadata.dtd
> 15:02:55,328 INFO  [STDOUT] systemId: 
> file:///C:/jboss-3.0.6/bin/SonyDAMAssetMet
> adata.dtd
> 15:02:55,328 INFO  [STDOUT] publicId: null
> 15:02:55,328 INFO  [STDOUT] dtdLocation is: 
> http://localhost:8080/data/SonyDAMAs
> setMetadata.dtd
> 15:02:55,343 INFO  [STDOUT] got the inputstream
> -----------------------------output---------------------------
> -------------
> 
> FYI: The application is running on JBoss appserver.
> 
> As I said, in my previous reponse to Richard, the server is 
> running in jboss/bin directory and so the systemId is being 
> set to file:///C:/jboss-3.0.6/bin/SonyDAMAssetMetadata.dtd. 
> And I am not sure how will the publicId be set! Will it ever 
> be set and/or used? This is what makes me so uncomfortable 
> with EntityResolver.
> 
> FYI: This is the transformation code:
> 
> ####################################Transformation
> code###########################
>    TransformerFactory tFactory = TransformerFactory.newInstance();
> 
>    Transformer transformer = tFactory.newTransformer(new 
> StreamSource(new URL(stylesheet).openStream()));
> 
>    InputStream inputStream = 
> req.getContentObject().getMetadataInputStream();
>    OutputStream outputStream = 
> req.getContentObject().getMetadataOutputStream();
> 
>    SAXParserFactory pfactory= SAXParserFactory.newInstance();
>    pfactory.setValidating(true);
>    // Get an XMLReader.
>    XMLReader reader = pfactory.newSAXParser().getXMLReader();
> 
>    //create a resolver to resolve the DTD in the source xml
>    reader.setEntityResolver(new DTDResolver());
>    DTDResolver resolver = (DTDResolver)reader.getEntityResolver();
>    resolver.setDtdLocation(this.dtdURL);
> 
>    SAXSource source = new SAXSource(reader,
>      new InputSource(new InputStreamReader(inputStream))); 
> //not sure if this is right! //if i don't have this, it 
> throws an exception saying it cannot find "SonyDAMAssetMetadata.dtd"
>    source.setSystemId("SonyDAMAssetMetadata.dtd");
> 
>    transformer.transform(source, new StreamResult(new 
> OutputStreamWriter(outputStream, "iso-8859-1"))); 
> ##############################################################
> ##############
> #################
> 
> Hope you found more info about my problem to help me better:-)!
> 
> Thanks,
> 
> Pramodh.
> 


Re: resolving DTDs while transforming

Posted by Pramodh Peddi <pe...@contextmedia.com>.
Thanx for the response Gary.

Sorry for the confusion on publicId thing. Though, I think it is right, it
is very confusing. I fixed that.

Reg'g the set and get methods in the DTDResolver class: I have to pass the
dtd's URL (to be used as dtd) to the DTDResolver class, so that it can
return the InputSource of that url. Thats the reason it has a get and a set
method for dtdLocation. I cleaned the class and used this code3, which
doesn't work either. It still generates an empty string after transforming
the source (as I said, its not exactly empty, it has just xml header in
it...that too not with the intended encoding). This is my DTDesolver I am
using right now. It is invoking the resolveEntity method of the DTDResovler
class.

***********************DTDResolver*******************
 class DTDResolver implements EntityResolver {
  String dtdLocation = null;

  public void setDtdLocation(String string){
   this.dtdLocation = string;
   System.out.println("Setting dtdURL: " + this.dtdLocation);
  }

  public String getDtdLocation(){
   System.out.println("Getting publicId");
   return this.dtdLocation;
  }

  public InputSource resolveEntity (String publicId, String systemId){
    InputStream inputStream = null;
    InputSource source = null;
    try{
       System.out.println("systemId: " + systemId);
     System.out.println("publicId: " + publicId);
     System.out.println("dtdLocation is: " + this.dtdLocation);
     if(StringUtils.isNotEmpty(this.dtdLocation)){

     URL url = new URL(this.dtdLocation);

     inputStream = url.openStream();
     System.out.println("got the inputstream");
     source = new InputSource(inputStream);
     }else{
    System.out.println("publicId is not specified!!!");
     }
    }catch(Exception e){
       e.printStackTrace();
  }

  return source;

   }
 }//end DTDResolver
*****************************************

And this is the output I am getting:

--------------------------------output-------------------------------
15:02:55,328 INFO  [STDOUT] Setting dtdLocation:
http://localhost:8080/data/SonyDAMAs
setMetadata.dtd
15:02:55,328 INFO  [STDOUT] systemId:
file:///C:/jboss-3.0.6/bin/SonyDAMAssetMet
adata.dtd
15:02:55,328 INFO  [STDOUT] publicId: null
15:02:55,328 INFO  [STDOUT] dtdLocation is:
http://localhost:8080/data/SonyDAMAs
setMetadata.dtd
15:02:55,343 INFO  [STDOUT] got the inputstream
-----------------------------output----------------------------------------

FYI: The application is running on JBoss appserver.

As I said, in my previous reponse to Richard, the server is running in
jboss/bin directory and so the systemId is being set to
file:///C:/jboss-3.0.6/bin/SonyDAMAssetMetadata.dtd. And I am not sure how
will the publicId be set! Will it ever be set and/or used? This is what
makes me so uncomfortable with EntityResolver.

FYI: This is the transformation code:

####################################Transformation
code###########################
   TransformerFactory tFactory = TransformerFactory.newInstance();

   Transformer transformer = tFactory.newTransformer(new StreamSource(new
URL(stylesheet).openStream()));

   InputStream inputStream =
req.getContentObject().getMetadataInputStream();
   OutputStream outputStream =
req.getContentObject().getMetadataOutputStream();

   SAXParserFactory pfactory= SAXParserFactory.newInstance();
   pfactory.setValidating(true);
   // Get an XMLReader.
   XMLReader reader = pfactory.newSAXParser().getXMLReader();

   //create a resolver to resolve the DTD in the source xml
   reader.setEntityResolver(new DTDResolver());
   DTDResolver resolver = (DTDResolver)reader.getEntityResolver();
   resolver.setDtdLocation(this.dtdURL);

   SAXSource source = new SAXSource(reader,
     new InputSource(new InputStreamReader(inputStream)));
//not sure if this is right!
//if i don't have this, it throws an exception saying it cannot find
"SonyDAMAssetMetadata.dtd"
   source.setSystemId("SonyDAMAssetMetadata.dtd");

   transformer.transform(source, new StreamResult(new
OutputStreamWriter(outputStream, "iso-8859-1")));
############################################################################
#################

Hope you found more info about my problem to help me better:-)!

Thanks,

Pramodh.


RE: resolving DTDs while transforming

Posted by Gary L Peskin <ga...@firstech.com>.
Just some further thoughts.

Your DTDResolver class is very confusing because you have publicId as both a
field in the class and as a method parameter to the resolveEntity method.
Simplify your DTDResolver class to look like this:

class DTDResolver implements EntityResolver
{
  public InputSource resolveEntity (String publicId, String systemId)
  {
    InputStream inputStream = null;
    InputSource source = null;

    try
    {
      System.out.println("publicID is: " + publicId);
      System.out.println("systemID is: " + systemId);
 
      if(StringUtils.isNotEmpty(publicId))
      {
        // Next line should be the URL you actually want       
        URL url = new URL(publicId);
        System.out.println("URL is: " + url);
        inputStream = url.openStream();
        System.out.println("got the inputstream");
        source = new InputSource(new InputStreamReader(inputStream));
      }
      else
      { 
        System.out.println("publicId is not specified!!!");
      }
    }
    catch (Exception e)
    {
      System.out.println("Caught exception " + e);
      e.printStackTrace();
    }
  }
} // end DTDResolver class

BTW, InputSource can take in the inputStream directly.  No need to construct
the InputStreamReader yourself.

HTH,
Gary

> -----Original Message-----
> From: Gary L Peskin [mailto:garyp@firstech.com] 
> Sent: Wednesday, December 17, 2003 11:34 AM
> To: 'Pramodh Peddi'; xalan-j-users@xml.apache.org
> Subject: RE: resolving DTDs while transforming
> 
> 
> Pramodh --
> 
> The entity resolver is not called by your code but by the 
> parser itself when it encounters the !DOCTYPE declaration.  
> You shouldn't be calling any of the setXXX methods in 
> DTDResolver yourself.
> 
> Does your DTDResolver.resolveEntity method ever get called? 
> Does the java statement
> 
>   System.out.println("publicID is: " + this.publicId);
> 
> result in any output?
> 
> I'd also add in a System.out.println() for the systemID.
> 
> Step 1 is to determine if the method is even getting called.  
> If so, we'll need to look at both arguments passed into that method.
> 
> HTH,
> Gary


RE: resolving DTDs while transforming

Posted by Gary L Peskin <ga...@firstech.com>.
Pramodh --

The entity resolver is not called by your code but by the parser itself when
it encounters the !DOCTYPE declaration.  You shouldn't be calling any of the
setXXX methods in DTDResolver yourself.

Does your DTDResolver.resolveEntity method ever get called?
Does the java statement

  System.out.println("publicID is: " + this.publicId);

result in any output?

I'd also add in a System.out.println() for the systemID.

Step 1 is to determine if the method is even getting called.  If so, we'll
need to look at both arguments passed into that method.

HTH,
Gary

> -----Original Message-----
> From: Pramodh Peddi [mailto:peddip@contextmedia.com] 
> Sent: Wednesday, December 17, 2003 8:29 AM
> To: xalan-j-users@xml.apache.org
> Subject: resolving DTDs while transforming
> 
> 
> Hi,
> I posted a requestion and I did not get any response back. I 
> thought it was
> difficult to understand what I asked in my previous post.
> Here is a better way of explaining my question(s):
> I have an xml source, to be transformed, which has a relative 
> DTD reference
> (just the dtd filename is specified), like:
> <?xml version="1.0" encoding="iso-8859-1"?>
> <!DOCTYPE CONTENT_FEED SYSTEM "myDTD.dtd">
> <root>
> ......
> ....
> </root>
> 
> The problem is myDTD.dtd is available NEITHER in the 
> classpath NOR where the
> class file is located. But, it is available in a 
> http-accessible location,
> like: http://myserver.com/dtd/myDTD.dtd.
> 
> So, I would like to tell the parser to consider
> "http://myserver.com/dtd/myDTD.dtd" instead of myDTD.dtd to 
> validate the
> source xml. (I know thats a stupid way of referring to a DTD, 
> but thats the
> customer's feed and they cannot change it).
> 
> I know this may not be related to transformation, but was 
> wondering if you
> kindly can help me.
> 
> Can any one help me get an approach.
> 
> Here is what I am doing: I am using Java1.4 API to transform. 
> I am using
> SAXSource to provide the xml source to the transformer. I am using
> EntityResolver interface to resolve the DTD (to let the 
> parser consider the
> http://myserver.com/dtd/myDTD.dtd in place of myDTD.dtd, 
> mentioned in the
> source xml). I just have an idea how to do, but it does not 
> work and no
> wonder because I do not yet clearly understand how 
> EntityResolver works.
> Questions Like: What is the role of systemID, publicID, when 
> does the parser
> try to resolve entities (like DTDs), etc. Can anyone give a clear
> understanding of how it works.
> 
> I hesitate giving the code, because the email becomes too large and
> incognizable. But, in case it helps you help me better, here 
> is the code:
> 
> *********************************************code*************
> **************
> ************
> public class SELTransformationService{
> 
> private String stylesheet;
> private String fileName = null;
> private String dtdURL = null;
> 
> private void transform(String metadata, String stylesheet,
> ServiceRequest req, ServiceResponse res){
> 
> //System.out.println("TRANSFORM USING STRING");
> 
> try {
> 
> TransformerFactory tFactory = TransformerFactory.newInstance();
> 
> Transformer transformer = tFactory.newTransformer(new StreamSource(new
> URL(stylesheet).openStream()));
> 
> InputStream inputStream =
> req.getContentObject().getMetadataInputStream();
> 
> OutputStream outputStream =
> req.getContentObject().getMetadataOutputStream();
> 
> SAXParserFactory pfactory= SAXParserFactory.newInstance();
> 
> pfactory.setValidating(true);
> 
> // Get an XMLReader.
> 
> XMLReader reader = pfactory.newSAXParser().getXMLReader();
> 
> //create a resolver to resolve the DTD in the source xml
> 
> //EntityResolver resolver = new DTDResolver();
> 
> reader.setEntityResolver(new DTDResolver());
> 
> DTDResolver resolver = (DTDResolver)reader.getEntityResolver();
> 
> resolver.setPublicId(this.dtdURL);
> 
> SAXSource source = new SAXSource(reader,
> 
> new InputSource(new InputStreamReader(inputStream)));
> 
> source.setSystemId("myDTD.dtd");
> 
> transformer.transform(source, new StreamResult(new
> OutputStreamWriter(outputStream, "iso-8859-1")));
> 
> outputStream.close();
> 
> req.getContentObject().commit();
> 
> res.send(req.getContentObject());
> 
> log.info(fileName + " - OBJECT SENT OUT OF TRANSFORMATION-2");
> 
> } catch (Exception ex) {
> 
> res.error(req.getContentObject(), "Exception sending message 
> to bus.");
> 
> ex.printStackTrace();
> 
> }
> 
> }//end SELTransformationService classclass DTDResolver implements
> EntityResolver {
> 
> String publicId = null;
> 
> public void setPublicId(String publicId){
> 
> this.publicId = publicId;
> 
> System.out.println("Setting publicID");
> 
> }
> 
> public String getPublicId(){
> 
> System.out.println("Getting publicId");
> 
> return this.publicId;
> 
> }
> 
> public InputSource resolveEntity (String publicId, String systemId){
> 
> InputStream inputStream = null;
> 
> InputSource source = null;
> 
> try{
> 
> System.out.println("publicID is: " + this.publicId);
> 
> if(StringUtils.isNotEmpty(this.publicId)){
> 
> URL url = new URL(this.publicId);
> 
> inputStream = url.openStream();
> 
> System.out.println("got the inputstream");
> 
> source = new InputSource(new InputStreamReader(inputStream));
> 
> }else{
> 
> System.out.println("publicId is not specified!!!");
> 
> }
> 
> }catch(Exception e){
> 
> }
> 
> return source;
> 
> }
> 
> }//end DTDResolver class
> **********************************************code************
> **************
> **************
> 
> When I do what is given above, the transformed string has 
> empty xml (has
> only xml header). I am sure I am doing something wrong. Can 
> any one tell me
> what is wrong in that. And making me understand how 
> EntityResolver works
> makes me feel lot better.
> 
> Thanks,
> 
> Pramodh.
>