tags:

views:

352

answers:

2

I want to add an xml:base declaration to an xml file in java. I currently have the xml output in an OutputStream that was generated by some third party code.

The file starts out like this:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns="http://www.mycompany.com/myNS#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"&gt;

And I want it to look like this:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns="http://www.mycompany.com/myNS#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xml:base="http://www.mycompany.com/myNS"&gt;

I must be having a brain fart or something, because I can't think of a good way to do this pragmatically.

Any ideas?

A: 

After some digging, this is what I did.

NOTE: I had the third party app write the xml to a StringWriter instead of an output stream named 'writer'. 'outputStream' is the name of the stream the resulting XML will be written to.

ByteArrayInputStream inputStream = new ByteArrayInputStream(writer.toString().getBytes());
Document myXML = 
     DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream);
myXML.getDocumentElement().setAttribute("xml:base", namespace);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StreamResult result = new StreamResult(outputStream);
DOMSource source = new DOMSource(myXML);
transformer.transform(source, result);

I really thought this would be easier.

Vinnie
A: 

The ByteArrayInputStream won't scale for large files, and I didn't like the idea of using a temp file. I also thought it was overkill to load the whole file into the DOM just to add the xml:base tag.

Here's an alternate solution using pipes and a simple hand rolled parsing code to add the tag.

PipedInputStream pipedInput = new PipedInputStream();
PipedOutputStream pipedOutput = new PipedOutputStream(pipedInput);
new Thread(new ModelExportThread(model, pipedOutput)).start();
int bufferSize = 1024;
byte[] bytes = new byte[bufferSize];            
StringBuffer stringBuffer = new StringBuffer();
int bytesRead = pipedInput.read(bytes, 0, bufferSize);
boolean done = false;
String startRDF = "<rdf:RDF";
while (bytesRead > 0) {
    if (!done) {
        stringBuffer.append(new String(bytes, 0, bytesRead));
        int startIndex = stringBuffer.indexOf(startRDF);
        if ((startIndex >= 0)) {
            stringBuffer.insert(startIndex + startRDF.length(), " xml:base=\"" + namespace + "\"");
            outputStream.write(stringBuffer.toString().getBytes());
            stringBuffer.setLength(0);
            done = true;
        }
    } else {
        outputStream.write(bytes, 0, bytesRead);
    }
    bytesRead = pipedInput.read(bytes, 0, bufferSize);
}
outputStream.flush();

Here's the threaded code to write to the output pipe.

public class ModelExportThread implements Runnable {

    private final OntModel model;
    private final OutputStream outputStream;

    public ModelExportThread(OntModel model, OutputStream outputStream) {
        this.model = model;
        this.outputStream = outputStream;
    }

    public void run() {
        try {
            model.write(outputStream, "RDF/XML-ABBREV");
            outputStream.flush();
            outputStream.close();
        } catch (IOException ex) {
            Logger.getLogger(OntologyModel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}
Vinnie