Parsing XML - quality-manager/onboarding GitHub Wiki
Background
We use a lot of XML in QM. You'll often find that in order to get something done you need to parse XML from a file or a String into a Document. There are any number of ways to do this and a lot of them require quite a bit of code.
The current best practice is to use what is called an "Identity Transformation" but the JAXP transformation API isn't an intuitive API to work with. As such, we've created our own API to abstract away a lot of the complexity of using that API for the most common cases. Unless you need to do something really fancy, you should use QM's Transformation Builder API.
The Right Way
Use QM's Transformation Builder API to parse XML in most cases.
Parse a String
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import org.w3c.dom.Document;
import com.ibm.rqm.common.xml.transform.Results;
import com.ibm.rqm.common.xml.transform.Transformation;
class StringToXmlParser
{
private final SAXTransformerFactory transformerFactory;
public StringToXmlParser(SAXTransformerFactory transformerFactory) {
this.transformerFactory = transformerFactory;
}
public Document toDOM(String xml) {
DOMResult result = DOMResult result = Results.makeDomResult();
Transformation.builder(transformerFactory)
.setSource(xml)
.setResult(result)
.build()
.transform();
return (Document) result.getNode();
}
}
Parse a File on the Classpath
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import org.w3c.dom.Document;
import com.ibm.rqm.common.xml.transform.Results;
import com.ibm.rqm.common.xml.transform.Sources;
import com.ibm.rqm.common.xml.transform.Transformation;
class FileToXmlParser
{
private final SAXTransformerFactory transformerFactory;
public FileToXmlParser(SAXTransformerFactory transformerFactory) {
this.transformerFactory = transformerFactory;
}
public Document toDOM(String filePath) throws ParserConfigurationException {
Source source = Sources.fromClasspath(filePath, getClass().getClassLoader());
DOMResult result = Results.makeDomResult();
Transformation.builder(transformerFactory)
.setSource(source)
.setResult(result)
.build()
.transform();
return (Document) result.getNode();
}
}
Note that in both cases we dependency inject the transformerFactory
. That is because a SAXTransformerFactory
is relatively expensive to create. As such, you'll want to cache an instance of this factory somewhere (probably a service instance) then inject it into any classes that need to do XML transformations.
Examples
- Style_UT#toDOM()
- AbstractPrinter#printTableSummary()
- XHTMLtoXSLFO#toXslfoDom()
- PdfExportOptions#toOptions()