0

I am using scala and play framework to create an API server. On one of my API calls, I upload a JSON and after some meddling on the server, I send back an XML. This XML should then be downloaded as a text file and I figured it was easiest if I directly start a download in the backend and don't just create the file in the front-end.

I have successfully created the XML I wanted using the scala.xml package and I do have now a node object, that when printed looks strikingly like the XML I am looking for.

Scala's scala.xml.XML object has a method, aptly called save that allows me to make a file out of the XML. I could use that to create my XML, but that means that I have to save it on the hard drive, which is its own can of worms. But I am kind of dead in the water in how to save the file in RAM. Can anyone help me out here?

EDIT 1:

To clarify, on the front-end side I am calling this API with axios. At my user's computer, there should be a downloading dialogue opening, asking my user where to save the file which might be called foo.xml. As I understand it, I need to transform my XML into a file stream. I can do this easily by just saving it on the hard drive and use java.nio on it, but I was hoping there was a way to avoid the write on the hard drive just to read it back into a file stream and then delete it routine.

SomeStranger314
  • 327
  • 1
  • 3
  • 12

2 Answers2

1

As far as I understood, you want to serve your clients an XML, i.e., sending an HTTP response with Content-Type: application/xml.

If this is what you want to do, then just pass your scala.xml.NodeSeq as an argument to your Ok call in the respective Action. As stated in the documentation, the Play Framework will automatically set the correct Content-Type in the response. There's no need to save the XML to a file beforehand, as you can directly send the XML as a response.

For example:

class MyController extends Controller {

  def processXml = Action { implicit request =>
    // Process XML
    val myXml: NodeSeq = getXml()
    Ok(myXml)
  }
}
Matthias A. Eckhart
  • 5,136
  • 4
  • 27
  • 34
  • Hello Matthias, thank you for your answer. I am not sure if that actually helps and it will be another hour before I can try it out, but I tried to clarify my request in Edit 1 of my initial question. Please take a look at it, if it is convenient for you. – SomeStranger314 May 16 '18 at 15:44
  • @SomeStranger314 This might be an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). What do you want to do? To me it sounds like you want to serve users HTTP responses with XML content. – Matthias A. Eckhart May 16 '18 at 15:52
  • I do have an XML in a `Node` object, that should be offered to the user as a download. It is not about just sending back XML instead of JSON. It is about sending back a text file with the extension `.xml` that the user can save on a place of his choosing. – SomeStranger314 May 16 '18 at 16:18
  • @SomeStranger314 Yes, that's what I thought, but how is this different from sending an HTTP response with the appropriate content type? Typically, browsers will visualize the XML, so no pop up will be opened, but users can still save the XML as a file. – Matthias A. Eckhart May 16 '18 at 16:30
  • Okay, it is solved. I did as you proposed and returned the value directly via `Ok(xmlNode)`. I did have it in my axios to do what I liked and I searched for front-end ways of creating the .xml file. And there is actually a very simple way, which I am now using. I will post this method in my own answer in a moment. Thank you for your help. Much appreciated. – SomeStranger314 May 16 '18 at 18:37
0

So, for everyone with a similar issue. It seems to be a much easier to change the data in the frontend and force the download.

I returned the data just as Matthias A. Eckhart suggested. And in the frontend I fed the data in this little function:

function download(filename, text) {
    const element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
    element.setAttribute('download', filename);

    element.style.display = 'none';
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);

This solution was found here: https://stackoverflow.com/a/18197341/9094259

Credits to Matěj Pokorný

SomeStranger314
  • 327
  • 1
  • 3
  • 12