Search code examples
javajaxbinputstreamstaxvtd-xml

How to get XML text as an Inputstream


I have the following client I am using to call a Jersey REST service.

public class JerseyClient {
    public static void main(String[] args) {
        ClientConfig config   = new DefaultClientConfig();
        Client       client   = Client.create(config);
        WebResource  service  = client.resource(getBaseURI());
        String       response = service.accept(MediaType.TEXT_XML)
                                       .header("Content-Type", "text/xml; charset=UTF-8")
                                       .entity(new File("E:/postx.xml"))
                                       .post(String.class);

        System.out.println(response);
    }

    private static URI getBaseURI() {
        return UriBuilder.fromUri("http://localhost:8080/MyService/rest/xmlServices/doSomething").build();
    }
}

Currently on the server side I have the following:

@POST
    @Path("/doSomething")
    @Consumes(MediaType.TEXT_XML)
    @Produces(MediaType.TEXT_XML)
    public Response consumeXMLtoCreate(ProcessJAXBObject jaxbObject) {

How do I change the above server side code so I can use stAX and stream one particular element to disk instead of converting all into objects into memory. My goal is to stream this element containing binary encoding data to disk.

The payload I receive is like this:

<?xml version="1.0" encoding="utf-8"?> <ProcessRequest> <DeliveryDate>2015-12-13</DeliveryDate>  <AttachmentBinary>iVBORw0KGgoAAAANSUhEUgAAAFoA</AttachmentBinary> <AttachmentBinary>iVBORw0KGgoAAAANSUhEUgAAAFoA</AttachmentBinary> </ProcessRequest>

Following advice from @vtd-xml-author

I now have the following:

Server side:

  @POST
    @Produces(MediaType.TEXT_XML)
    @Path("/doSomething")
    @Consumes(MediaType.APPLICATION_OCTET_STREAM)
    public Response consumeXMLtoCreate(@Context HttpServletRequest a_request,
            @PathParam("fileId") long a_fileId,
            InputStream a_fileInputStream) throws IOException {

        InputStream is;
        byte[] bytes = IOUtils.toByteArray(a_fileInputStream);

        VTDGen vg = new VTDGen();
        vg.setDoc(bytes);
        try {
            vg.parse(false);
        } catch (EncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (EOFException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (EntityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }//
        VTDNav vn = vg.getNav();
        AutoPilot ap = new AutoPilot(vn);
        try {
            ap.selectXPath("/ProcessRequest/BinaryAttachment/text()");
        } catch (XPathParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        int i=0;
        try {
            while((i=ap.evalXPath())!=-1){
               //i points to text node of 
               String s = vn.toRawString(i);
               System.out.println("HAHAHAHA:" + s);
              // you need to decode them 
            }
        } catch (XPathEvalException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NavException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

and client side I have this:

File file = new File("E:/postx.xml");
        FileInputStream fileInStream = null;

            fileInStream = new FileInputStream(file);

        ClientConfig config   = new DefaultClientConfig();
        Client       client   = Client.create(config);
        WebResource  service  = client.resource(getBaseURI());

         String tempImage = myfile.jpg;

        String sContentDisposition = "attachment; filename=\"" + tempImage+"\"";

        ClientResponse response = service.type(MediaType.APPLICATION_OCTET_STREAM)
                                       .header("Content-Disposition", sContentDisposition)
                                       .post(ClientResponse.class, fileInStream);

I have questions that arise from this solution, firstly how exactly am I avoiding the same memory issues if I end up with a String object in heap that I need to decode ?

Secondly can I reconstitute an object or inputStream using vtd-xml once I've removed the image elements as I'd then like to process this using JAXB ?

I believe XMLModifier's remove() method should allow me to have some sort of XML represent minus the element I have now written to disk.


Solution

  • I assume you know how to interface with HTTP protocol in your code..so you know how to read the bytes off the input stream into a byte buffer... the following code will take over from that point ...

    public void readBinaryAttachment(HTTPInputStream input) throws VTDException, IOException{
    // first read xml bytes into XMLBytes
    ....
    VTDGen vg = new VTDGen();
    vg.setDoc(XMLBytes);
    vg.parse(false);//
    VTDNav vn = vg.getNav();
    AutoPilot ap = new AutoPilot(vn);
    ap.selectXPath("/ProcessRequest/BinaryAttachment/text()");
    int i=0;
    while((i=ap.evalXPath())!=-1){
       //i points to text node of 
       String s = vn.toRawString(i);
      // you need to decode them 
    }
    
    }