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
Related
I have a xml file and I want to convert it into a java object using JAXB. I am getting an exception related to validation. It seems JAXB is validating it against the DTD which is declared in the xml file. Unfortunately the DTD is not at the location which is mentioned in the xml file. So I kept a local copy and used an EntityResolver to make JAXB use the local DTD. And the code worked like a charm.
Below is the code
JAXBContext context = JAXBContext.newInstance(Student.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
final XMLReader reader = saxParserFactory.newSAXParser().getXMLReader();
reader.setEntityResolver(new EntityResolver() {
#Override
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
return new InputSource(getClass().getResourceAsStream("/student.dtd"));
}
});
final SAXSource saxSource = new SAXSource(reader, new InputSource(inputStream));
student = (Student) unmarshaller.unmarshal(saxSource);
This code is inside my method parse(xmlFilePath). Every time I call parse method a new EntityResolver is created. Is this not redundant? Can I create one EntityResolver in the class's constructor and pass it to the setEntityResolver method?
public StudentParser() {
this.entityResolver = new EntityResolver() {
#Override
public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException, IOException {
return new InputSource(getClass().getResourceAsStream("/student.dtd"));
}
}
}
Inside parse method
public Student parse(filePath) {
...
...
reader.setEntityResolver(this.entityResolver);
...
}
First of all, check these answers:
How to disable DTD fetching using JAXB2.0
Make DocumentBuilder.parse ignore DTD references
How to read well formed XML in Java, but skip the schema?
How do I turn off validation when parsing well-formed XML using DocumentBuilder.parse?
How to ignore inline DTD when parsing XML file in Java
In short, you can disable the DTD processing completely.
Next, as long as your entity resolver is thread-safe and reusable you definitely don't need to create new instances every time.
After checking the answers from the other questions and applying them to my program, I still have problems loading assets from my Project.
Here is the block of code which has the problem and it seems to not go past the line with the comment //BUG
public void parseXmlFile(String xml_file, String object, String xml_class, String pointer, Activity activity, TextView test) throws ParserConfigurationException, SAXException, IOException{
view = test;
view.setText("2.1");
categories_list = new ArrayList<Category>();
//instantiate String object sto be used throughout class
object_name = object;
class_type = xml_class;
value_pointer = pointer;
//get factory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//get instance of document builder to build document from xml file
DocumentBuilder builder = factory.newDocumentBuilder();
//Create bytestream which allows a stream of data from xml to document builder
ByteArrayInputStream byte_stream = new ByteArrayInputStream(xml_file.getBytes("utf-8"));
//create an input source for the bytestream
InputSource input_src = new InputSource(activity.getAssets().open(xml_file));
dom = builder.parse(input_src); //BUG
parseDocument();
byte_stream.close();
}
My XML is in the assets folder and the app doesn't crash, it just doesn't do anything. The response i'm supposed to get is a listview of buttons gotten from the parsing of the XML. The algorithm to parse the XML works as it has been tested in a normal Java application. I just want to apply it to the Android app.
If you want more info just comment.
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);
i want to import an XML file into my Java application .
this is the function :
static void lireFichier(String fichier) throws Exception
{
SAXBuilder sxb = new SAXBuilder();
document = sxb.build(new File(fichier));
racine = document.getRootElement();
}
and this is how i call it
lireFichier("exemple.xml");
This is part of a Swing application. I want the user to be able to specify the XML file to open. How do I do this?
This is really a basic concept that could have been easily solved with minimal research.
You need to spend some time reading through Creating a GUI With JFC/Swing and How to Use File Choosers in particular.
I'd also recommend a crash course on the java.io.File API as well...
JFileChooser fc = new JFileChooser();
fc.setDialogTitle("Open stuff");
fc.addChoosableFileFilter(new FileFilter() {
#Override
public boolean accept(File f) {
return f.getName().toLowerCase().endsWith(".xml") || f.isDirectory();
}
#Override
public String getDescription() {
return "XML Document (*.xml)";
}
});
switch (fc.showOpenDialog(null)) {
case JFileChooser.APPROVE_OPTION:
File file = fc.getSelectedFile();
lireFichier(file.getPath());
break;
}
- Its simple, just pass the path of the File as String, where your XML file is located.
eg:
File f = new File("d:\\Myfolder\\vivek.xml");
- You can always also use the following easy to use APIs to parse the XML.
JAXP & JAXB
CASTOR
I'm using the Apache web service xml rpc library to make requests to an rpc service. Somewhere in that process is a xml document with a DTD reference to http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd, which the library attempts to download when parsing the XML. That download fails with a 503 status code because the w3c is blocking repeated downloads of this largely static document from Java clients.
The solution is XML Catalogs to locally cache the DTD. However, while I can find examples of setting an EntityHandler on a JAXP SAXParser instance directly to enable catalog parser support, I don't actually have access to the underlying parser here. It's just being used by the xml rpc library. Is there any way I can set a global property or something that will tell JAXP to use XML catalogs?
I think you want the system property xml.catalog.files.
Take a look at http://xml.apache.org/commons/components/resolver/resolver-article.html
BTW, this was the third hit on a Google search for jaxp catalog
Unfortunately, setting xml.catalog.files does NOT have any effect on the parser factory. Ideally it should, of course, but the only way to use a resolver is to somehow add a method that delegates resolution to the catalog resolver in the handler that the SAX parser uses.
If you are already using a SAX parser, that's pretty easy:
final CatalogResolver catalogResolver = new CatalogResolver();
DefaultHandler handler = new DefaultHandler() {
public InputSource resolveEntity (String publicId, String systemId) {
return catalogResolver.resolveEntity(publicId, systemId);
}
public void startElement(String namespaceURI, String lname, String qname,
Attributes attrs) {
// the stuff you'd normally do
}
...
};
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
SAXParser saxParser = factory.newSAXParser();
String url = args.length == 0 ? "http://horstmann.com/index.html" : args[0];
saxParser.parse(new URL(url).openStream(), handler);
Otherwise, you'll need to figure out if you can supply your own entity resolver. With a javax.xml.parsers.DocumentBuilder, you can. With the scala.xml.XML object, you can't but you can use subterfuge:
val res = new com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver
val loader = new factory.XMLLoader[Elem] {
override def adapter = new parsing.NoBindingFactoryAdapter() {
override def resolveEntity(publicId: String, systemId: String) = {
res.resolveEntity(publicId, systemId)
}
}
}
val doc = loader.load(new URL("http://horstmann.com/index.html"))enter code here