java - spring - xsl transformation dtd not found error - java

I have a code which transform xml file using xsl, my peace of code as following. My problem is when i run the execution point it gives me following error.
StackTrace: javax.xml.transform.TransformerException: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: /home/app/myapp/bin/xhtml11-flat.dtd (No such file or directory)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:720)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:313)
at com.core.util.XmlUtils.transform(XmlUtils.java:151)
at com.core.util.XmlUtils.transform(XmlUtils.java:147)
Long story short it is trying to find dtd file inside the bin directory from where i executed the application.
/home/app/myapp/bin/xhtml11-flat.dtd
I have the xhtml11-flat.dtd file if i copy this file in bin directory it works fine, instead of the bin directory i want to load it from classpath any idea how can i achieve this with minimum changes ?
I don't know from where it is laoding .dtd code so that i can set my path in it.
//Execution Point
function transform(){
Templates templates = getTemplates();
StringWriter result = new StringWriter();
XmlUtils.transform(templates.newTransformer(), input, new StreamResult(result));
...
}
private Templates getTemplates() throws Exception {
if (templates == null) {
templates = XmlUtils.createTemplates(XslRdcSourceDocTransformer.class.getResourceAsStream("/xsl/" + getXslFileName()));
}
return templates;
}
public static Templates createTemplates(InputStream stream) throws Exception {
TransformerFactory tfactory = TransformerFactory.newInstance();
return tfactory.newTemplates(new StreamSource(stream));
}

Your xml files are probably containing a doctype declaration containing a relative path to the dtd:
<!DOCTYPE html SYSTEM "xhtml11-flat.dtd">
The transformer api tries to resolve this path to the current working directory of the java program. To customize how the path is resolved you need to implement a EntityResolver. This EntityResolver can return an InputSource referring to a copy of the dtd loaded from the classpath.
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException {
if ("xhtml11-flat.dtd".equals(systemId)) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
InputSource is = new InputSource();
is.setSystemId(systemId);
is.setByteStream(cl.getResourceAsStream("/com/example/dtd/xhtml11-flat.dtd"));
return is;
} else {
return null;
}
}
How you use this class depends on the type of source for your transformation. For a DOMSource you have to configure the DocumentBuilder:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
DocumentBuilder builder = ...
builder.setEntityResolver(entityResolver);
Source source = new DOMSource(builder.parse(inputStream));
For a SAXSource the setting is on the XMLReader instance:
SAXParserFactory factory1 = SAXParserFactory.newInstance();
factory1.setValidating(false);
factory1.setNamespaceAware(true);
SAXParser parser = factory1.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
xmlreader.setEntityResolver(entityResolver);
Source source = new SAXSource(xmlreader, new InputSource(stream));
The code for the transformation is the same regardless of the source type and should look similar to the code you currently have in your XmlUtils class:
Templates templates = ...
Result result = new StreamResult(...);
Transformer transformer = templates.newTransformer();
transformer.transform(source, result);

Related

Adding a catalog to XSLT Saxon s9api in Java

I have the following code which takes XML as input and produces a bunch of other files as output.
public void transformXml(InputStream inputFileStream, Path outputDir) {
try {
Resource resource = resourceLoader
.getResource("classpath:demo.xslt");
LOGGER.info("Creating output XMLs and Assessment Report in {}", outputDir);
final File outputFile = new File(outputDir.toString());
final Processor processor = getSaxonProcessor();
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable stylesheet = compiler.compile(new StreamSource(resource.getFile()));
Xslt30Transformer transformer = stylesheet.load30();
Serializer out = processor.newSerializer(outputFile);
out.setOutputProperty(Serializer.Property.METHOD, "xml");
transformer.transform(new StreamSource(inputFileStream), out);
LOGGER.debug("Generated DTD XMLs and Assessment Report successfully in {}", outputDir);
} catch (SaxonApiException e) {
throw new XmlTransformationException("Error occured during transformation", e);
} catch (IOException e) {
throw new XmlTransformationException("Error occured during loading XSLT file", e);
}
}
private Processor getSaxonProcessor() {
final Configuration configuration = Configuration.newConfiguration();
configuration.disableLicensing();
Processor processor = new Processor(configuration);
return processor;
}
The XML input contains a DOCTYPE tag which resolves to a DTD that is not available to me. Hence why I am wanting to use a catalog to point it to a dummy DTD which is on my classpath.
I am struggling to find a way to this. Most examples that I find out there, are not using the s9api implementation. Any ideas?
Instead of
new StreamSource(inputFileStream)
you should instantiate a SAXSource, containing an XMLReader initialized to use the catalog resolver as its EntityResolver.
If you need to do the same thing for other source documents, such as those read using doc() or document(), you should supply a URIResolver which itself returns a SAXSource initialized in the same way.
There are other ways of doing it using Saxon configuration properties, but I think the above is the simplest.

Parsing dom error in java

I am trying to parse an XML and then insert it an Excel File.
If I run my code it works even with errors but I cannot make any modification to it because I still got errors. Here is my code:
public class Parsing {
private void parseXmlFile(){
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//using Factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation
dom = db.parse("Employee.xml"); }
} catch )
}
}
What is wrong with this?
Can someone help me? I've been searching all over google and it's eating my nerves.
it should be like this :-
private void parseXmlFile(){
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//using Factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation
Document dom = db.parse("Employee.xml");
} catch(IOException ex ){ // OR Any Specific Exception should be catched here
// your error handling code here
}
}
Also Employee.xml should be in the current directory or give complete abosulte path of Employee.xml file also.

How to reference an xml file from resources? Eclipse

I'm parsing in an xml file using SAX and need to add it as a resource instead of hard coding the file path.
I set up the file path y using a string like this:
private static final String GAME_FILE = "game.xml";
Its been suggested to use getResourceAsStream but I'm not sure how to apply that to my solution.
Does anyone how the reference the file from resources instead within the project?
This is how I reference the xml file by just adding it to the root of the project, which is bad practice:
public class Parser extends DefaultHandler{
private static final String GAME_FILE = "game.xml";
//You should have a boolean switch for each XML element, but not attribute
boolean location = false;
boolean description = false;
boolean item = false;
boolean gameCharacter = false;
boolean searchAlgorithm = false;
//Read in the XML file game.xml and use the current object as the SAX event handler
public void parse() throws ParserConfigurationException, SAXException, IOException{
XMLReader xmlReader = null;
SAXParserFactory spfactory = SAXParserFactory.newInstance();
spfactory.setValidating(false);
SAXParser saxParser = spfactory.newSAXParser();
xmlReader = saxParser.getXMLReader();
xmlReader.setContentHandler(this);
InputSource source = new InputSource(GAME_FILE);
xmlReader.parse(source);
xmlReader.setErrorHandler(this);
}
Below shows the project structure after adding the file to a resources folder, but adding it to the resources folder, causes the file to not be found.
The problem is that game.xml is technically in the "resources" packages. Thus using
GAME_FILE = "/resources/game.xml"
InputSource source = new InputSource(getClass().getResourceAsStream(GAME_FILE));
should do the trick

Glassfish using Saxon instead of Xalan, XSLT 2.0, Java

I have a problem with transforming a XML (TEI P5) to PDF. My Stylesheet is from TEI https://github.com/TEIC/Stylesheets and I call the file fo/fo.xsl. When I transform my XML using Oxygen and Saxon there is no Problem, the PDF will be generated. But in my J2EE application the transform does not work. I think because of the XSLT 2.0. So i wanted to change to an other parser. I downloaded Saxon 9HE and included it in my project. Then I experimented and changed the java call and it looks now like this:
String inputXSL2 = "/de/we/parser/xslt/fo/fo.xsl";
String inputXML2 = "/de/we/parser/testfiles/Presentation.xml";
Source xsltTarget = new StreamSource(inputXSL2);
try {
TransformerFactory tFactory = TransformerFactory.newInstance();
tFactory.setURIResolver(new XsltURIResolver());
Transformer transformer = tFactory.newTransformer(xsltTarget);
Controller controller = (net.sf.saxon.Controller) transformer;
Configuration configuration = controller.getConfiguration();
configuration.setConfigurationProperty(FeatureKeys.PRE_EVALUATE_DOC_FUNCTION, Boolean.TRUE);
Source source = transformer.getURIResolver().resolve(inputXML2, "");
DocumentInfo newdoc = configuration.buildDocument(source);
configuration.getGlobalDocumentPool().add(newdoc, inputXML2);
Source streamSource = null;
StreamResult resultTarget = null;
streamSource = new StreamSource(new StringReader(inputXML2));
resultTarget = new StreamResult(new StringWriter());
transformer.transform(streamSource, resultTarget);
} catch (Exception e) {
System.out.println(e);
}
class XsltURIResolver implements URIResolver {
#Override
public Source resolve(String href, String base) throws TransformerException {
try {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("/de/we/parser/xslt/fo/" + href);
StreamSource ss = new StreamSource(inputStream);
ss.setSystemId("/de/we/parser/xslt/fo/" + href);
return ss;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
The error is:
I/O error reported by XML parser processing /de/we/parser/xslt/fo/fo.xsl:
\de\we\parser\xslt\fo\fo.xsl (Das System kann den angegebenen Pfad nicht finden)
But the file exists so i don't know whats the problem.
Had a lot other version where I tried to use Saxon, but the result was never a generated pdf :(
Need some help please
Please don't crosspost to multiple lists.
You asked the same question here
https://saxonica.plan.io/boards/3/topics/5849?r=5851#message-5851
where I answered it.

Validating XML files in Java against two schemas with same namespace

I have
an XML document,
base XSD file and
extended XSD file.
Both XSD files have one namespace.
File 3) includes file 2): <xs:include schemaLocation="someschema.xsd"></xs:include>
XML document (file 1) has following root tag:
<tagDefinedInSchema xmlns="http://myurl.com/myapp/myschema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://myurl.com/myapp/myschema schemaFile2.xsd">
where schemaFile2.xsd is the file 3 above.
I need to validate file 1 against both schemas, without
modifying the file itself and
merging two schemas in one file.
How can I do this in Java?
UPD: Here is the code I'm using.
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
DocumentBuilderFactory documentFactory = DocumentBuilderFactory
.newInstance();
documentFactory.setNamespaceAware(namespaceAware);
DocumentBuilder builder = documentFactory.newDocumentBuilder();
Document document = builder.parse(new ByteArrayInputStream(xmlData
.getBytes("UTF-8")));
File schemaLocation = new File(schemaFileName);
Schema schema = schemaFactory.newSchema(schemaLocation);
Validator validator = schema.newValidator();
Source source = new DOMSource(document);
validator.validate(source);
UPD 2: This works for me:
public static void validate(final String xmlData,
final String schemaFileName, final boolean namespaceAware)
throws SAXException, IOException {
final SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
schemaFactory.setResourceResolver(new MySchemaResolver());
final Schema schema = schemaFactory.newSchema();
final Validator validator = schema.newValidator();
validator.setResourceResolver(schemaFactory.getResourceResolver());
final InputSource is = new InputSource(new ByteArrayInputStream(xmlData
.getBytes("UTF-8")));
validator.validate(new SAXSource(is), new SAXResult(new XMLReaderAdapter()));
}
class MySchemaResolver implements LSResourceResolver {
#Override
public LSInput resolveResource(final String type,
final String namespaceURI, final String publicId, String systemId,
final String baseURI) {
final LSInput input = new DOMInputImpl();
try {
if (systemId == null) {
systemId = SCHEMA1;
}
FileInputStream fis = new FileInputStream(
new File("path_to_schema_directory/" + systemId));
input.setByteStream(fis);
return input;
} catch (FileNotFoundException ex) {
LOGGER.error("File Not found", ex);
return null;
}
}
}
A bit of terminology: you have one schema here, which is built from two schema documents.
If you specify schemaFile2.xsd to the API when building the Schema, it should automatically pull in the other document via the xs:include. If you suspect that this isn't happening, you need to explain what the symptoms are that cause you to believe this.
It may seem a bit inefficient, but couldn't you validate against schema A, create a new validator using schema B and validate against that one too?

Categories

Resources