I am trying to find a way to convert Document to String and found this XML Document to String? post here. But, I want to do the conversion without using TransformerFactory because of XXE Vulnerabilities and by using DocumentBuilderFactory only. I cannot upgrade to jdk8 because of other limitations.
I haven't had any luck so far with it; all the searches are returning the same code shown in the above link.
Is it possible to do this?
This is difficult to do, but since your actual problem is the security vulnerability and not TransformerFactory, that may be a better way to go.
You should be able to configure TransformerFactory to ignore entities to prevent this sort of problem. See: Preventing XXE Injection
Another thing that may work for your security concerns is to use TransformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING). This should prevent the problems that you're worried about. See also this forum thread on coderanch.
Setting FEATURE_SECURE_PROCESSING may or may not help, depending on what implementation TransformerFactory.getInstance() actually returns.
For example in Java 7 with no additional XML libraries on classpath setting transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); does not help.
You can fix this by providing a Source other than StreamSource (which factory would need to parse using some settings that you do not control).
For example you can use StAXSource like this:
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); // does not help in Java 7
Transformer transformer = transformerFactory.newTransformer();
// StreamSource is insecure by default:
// Source source = new StreamSource(new StringReader(xxeXml));
// Source configured to be secure:
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLEventReader xmlEventReader = xif.createXMLEventReader(new StringReader(xxeXml));
Source source = new StAXSource(xmlEventReader);
transformer.transform(
source,
new StreamResult(new ByteArrayOutputStream()));
Note the actual TrasformerFactory may not actually support StAXSource, so you need to test your code with the classpath as it would be on production. For example Saxon 9 (old one, I know) does not support StAXSource and the only clean way of "fixing" it that I know is to provide custom net.sf.saxon.Configuration instance.
Related
I am producing compiled .class files (Translet) from XSL transformation files with using TransformerFactory which is implemented by org.apache.xalan.xsltc.trax.TransformerFactoryImpl.
Unfortunately, I couldn't find the way how to use these translet classes on XML transformation despite my searchings for hours.
Is there any code example or reference documentation may you give? Because this document is insufficient and complicated.
Thanks.
A standard transformation in XSLT looks like this:
public void translate(InputStream xmlStream, InputStream styleStream, OutputStream resultStream) {
Source source = new StreamSource(xmlStream);
Source style = new StreamSource(styleStream);
Result result = new StreamResult(resultStream);
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer t = tFactory.newTransformer(style);
t.transform(source, result);
}
so given that you don't use a Transformer factory, but a ready made Java class (which is an additional maintenance headache and doesn't give you that much better performance since you can keep your transformer object after the initial compilation) the same function would look like this:
public void translate(InputStream xmlStream, OutputStream resultStream) {
Source source = new StreamSource(xmlStream);
Result result = new StreamResult(resultStream);
Translet t = new YourTransletClass();
t.transform(source, result);
}
In your search you missed out to type the Interface specification into Google where the 3rd link shows the interface definition, that has the same call signature as Transformer. So you can swap a transformer object for your custom object (or keep your transformer objects in memory for reuse)
Hope that helps
Mostly continued from this question: XSLT: CSV (or Flat File, or Plain Text) to XML
So, I have an XSLT from here: http://andrewjwelch.com/code/xslt/csv/csv-to-xml_v2.html
And it converts a CSV file to an XML document. It does this when used with the following command on the command line:
java -jar saxon9he.jar -xsl:csv-to-xml.csv -it:main -o:output.xml
So now the question becomes: How do I do I do this in my Java code?
Right now I have code that looks like this:
TransformerFactory transformerFactory = TransformerFactory.newInstance();
StreamSource xsltSource = new StreamSource(new File("location/of/csv-to-xml.xsl"));
Transformer transformer = transformerFactory.newTransformer(xsltSource);
StringWriter stringWriter = new StringWriter();
transformer.transform(documentSource, new StreamResult(stringWriter));
String transformedDocument = stringWriter.toString().trim();
(The Transformer is an instance of net.sf.saxon.Controller.)
The trick on the command line is to specify "-it:main" to point right at the named template in the XSLT. This means you don't have to provide the source file with the "-s" flag.
The problem starts again on the Java side. Where/how would I specify this "-it:main"? Wouldn't doing so break other XSLT's that don't need that specified? Would I have to name every template in every XSLT file "main?" Given the method signature of Transformer.transform(), I have to specify the source file, so doesn't that defeat all the progress I've made in figuring this thing out?
Edit: I found the s9api hidden inside the saxon9he.jar, if anyone is looking for it.
You are using the JAXP API, which was designed for XSLT 1.0. If you want to make use of XSLT 2.0 features, like the ability to start a transformation at a named template, I would recommend using the s9api interface instead, which is much better designed for this purpose.
However, if you've got a lot of existing JAXP code and you don't want to rewrite it, you can usually achieve what you want by downcasting the JAXP objects to the underlying Saxon implementation classes. For example, you can cast the JAXP Transformer as net.sf.saxon.Controller, and that gives you access to controller.setInitialTemplate(); when it comes to calling the transform() method, just supply null as the Source parameter.
Incidentally, if you're writing code that requires a 2.0 processor then I wouldn't use TransformerFactory.newInstance(), which will give you any old XSLT processor that it finds on the classpath. Use new net.sf.saxon.TransformerFactoryImpl() instead, which (a) is more robust, and (b) much much faster.
Trying to figure out a way to strip out specific information(name,description,id,etc) from an html file leaving behind the un-wanted information and storing it in an xml file.
I thought of trying using xslt since it can do xml to html... but it doesn't seem to work the other way around.
I honestly don't know what other language i should try to accomplish this. i know basic java and javascript but not to sure if it can do it.. im kind of lost on getting this started.
i'm open to any advice/help. willing to learn a new language too as i'm just doing this for fun.
There are a number of Java libraries for handling HTML input that isn't well-formed (according to XML). These libraries also have built-in methods for querying or manipulating the document, but it's important to realize that once you've parsed the document it's usually pretty easy to treat it as though it were XML in the first place (using the standard Java XML interfaces). In other words, you only need these libraries to parse the malformed input; the other utilities they provide are mostly superfluous.
Here's an example that shows parsing HTML using HTMLCleaner and then converting that object into a standard org.w3c.dom.Document:
TagNode tagNode = new HtmlCleaner().clean("<html><div><p>test");
DomSerializer ser = new DomSerializer(new CleanerProperties());
org.w3c.dom.Document doc = ser.createDOM(tagNode);
In Jsoup, simply parse the input and serialize it into a string:
String text = Jsoup.parse("<html><div><p>test").outerHtml();
And convert that string into a W3C Document using one of the methods described here:
How to parse a String containing XML in Java and retrieve the value of the root node?
You can now use the standard JAXP interfaces to transform this document:
TransformerFactory tFact = TransformerFactory.newInstance();
Transformer transformer = tFact.newTransformer();
Source source = new DOMSource(doc);
Result result = new StreamResult(System.out);
transformer.transform(source, result);
Note: Provide some XSLT source to tFact.newTransformer() to do something more useful than the identity transform.
I would use HTMLAgilityPack or Chris Lovett's SGMLReader.
Or, simply HTML Tidy.
Ideally, you can treat your HTML as XML. If you're lucky, it will already be XHTML, and you can process it as HTML. If not, use something like http://nekohtml.sourceforge.net/ (a HTML tag balancer, etc.) to process the HTML into something that is XML compliant so that you can use XSLT.
I have a specific example and some notes around doing this on my personal blog at http://blogger.ziesemer.com/2008/03/scraping-suns-bug-database.html.
TagSoup
JSoup
Beautiful Soup
I have a simple code for transforming XML, but it is very time consuming (I have to repeat it many times). Does anyone have a recommendation how to optimize this code? Thanks.
EDIT: This is a new version of the code. I unfortunatelly can't reuse Transformer, since XSLTRuleis in most of the cases different. I'm now reusing TransformerFactory. I'm not reading from files before this so I can't use StreamSource. Largest amount of time is spent on initialization of Transformer.
private static TransformerFactory tFactory = TransformerFactory.newInstance();
public static String transform(String XML, String XSLTRule) throws TransformerException {
Source xmlInput = new StreamSource(new StringReader(XML));
Source xslInput = new StreamSource(new StringReader(XSLTRule));
Transformer transformer = tFactory.newTransformer(xslInput);
StringWriter resultWriter = new StringWriter();
Result result = new StreamResult(resultWriter);
transformer.transform(xmlInput, result);
return resultWriter.toString();
}
The first thing you should do is to skip the unnecessary conversion of the XML string to bytes (especially with a hardcoded, potentially incorrect encoding). You can use a StringReader and pass that to the StreamSource constructor. The same for the result: use a StringWriter and avoid the conversion.
Of course, if you call the method after converting your XML from a file (bytes) to a String in the first place (again with a potentially wrong encoding), it would be even better to have the StreamSource read from the file directly.
It seems like you apply an XSLT to an XML file. To speed things up, you can try compiling the XSLT, like with XSLTC.
I can only think of a couple of minor things:
The TransformerFactory could be reused.
The Transformer could be reused if it is thread confined, and the XSL input is the same each time.
If you can estimate the output size reasonably accurately, you could create the ByteArrayOutputStream with an initial size hint.
As stated in Michaels answer, you could potentially speed things up by not loading either the input or output xml entirely into memory yourself and make your api stream based.
So the question is pretty much as stated in the title. I am doing some xml work and using XMLEventWriter. The big issue I'm having is that I need to create some self closing tags
The problem is that I haven't figured out a way to do this with the eventWriter. I have tried everything I can think of using XMLEventFactory but nothing seems to work. Any help would be greatly appreciated.
I'm not sure if this is possible using XMLEventWriter. It is certainly possible with XMLStreamWriter.
If you are stuck with XMLEventWriter, you could transform the data afterwards.
Reader xml = new StringReader("<?xml version=\"1.0\"?><foo></foo>");
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.transform(new StreamSource(xml),
new StreamResult(System.out));
The output of the above code is:
<?xml version="1.0" encoding="UTF-8"?><foo/>