I'm reading correctly an xml file, but I'm not able to write it.
Here is the file: a configuration file for key-value settings.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<setting key="Password" value="d92e1dedba95d2cf00d4c567e57e3342"/>
<setting key="ExceptionFileLog" value="exception.txt"/>
<setting key="ActionFileLog" value="actions.txt" />
<setting key="ShowInfoMessage" value="false" />
</configuration>
I correctly open and read file using javax.xml.parsers.DocumentBuilder:
private Document _doc = null;
public XmlConfig(String filePath) throws Exception
{
File xml = new File(filePath);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
_doc = dBuilder.parse(xml);
_doc.getDocumentElement().normalize();
}
So far so good, but I'm not able to write and persist changes to the file:
public boolean updateValue(String key, String value)
{
NodeList settlist = _doc.getElementsByTagName(SETTNAME);
for(int i = 0; i < settlist.getLength(); i++)
{
Element sett = (Element) settlist.item(i);
if(sett.getNodeType() == Node.ELEMENT_NODE)
{
if(null != sett.getAttribute("key") && sett.getAttribute("key").equals(key))
{
sett.setAttribute("value", value);
return true;
}
}
}
return false;
}
So, if I print xml file from _doc (Document object) the changes are correctly written, but xml file is not updated!
I suppose that I'm opening,reading and writing xml file in memory and I need a way to persist changes on disk.
I have no idea, any suggestion will be appreciated.
save the changed xml file using the following code
Transformer transformer = TransformerFactory.newInstance().newTransformer();
Result output = new StreamResult(xml); // xml is a object of File i.e. File xml = new File(filePath);
Source input = new DOMSource(_doc);
transformer.transform(input, output);
it will store the updated values in the xml file.
reference from how-to-save-parsed-and-changed-dom-document-in-xml-file
Related
The only Question i found that seemed similiar but sadly this didnt help
Hi so ive been stuck on this Problem for a few hours now.
I am trying to write new Data into an preexisting XML file (/creating it when it doesnt exist yet) for Data Collection for a small game i am programming for uni.
Ive created a DataRecorder class for this that works fine when testing with a main in that class
private Transformer transformer;
private Document documentWriter;
private DocumentBuilder documentBuilder;
private Element eventList;
private static final String RECORDED_DATA = "Game/src/main/resources/recordedData.xml";
public DataRecorder() {
recordedData = new ArrayList<Data>();
this.username = System.getProperty("user.name");
this.newData = false;
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
this.transformer = transformerFactory.newTransformer();
} catch (Exception e) {
System.out.println("Error when creating DataRecorder: Transformer");
}
File tempFile = new File(RECORDED_DATA);
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
this.documentBuilder = dbf.newDocumentBuilder();
if (!tempFile.exists()) {
//Creates new Document if it doesnt exist
this.documentWriter = this.documentBuilder.newDocument();
} else {
this.documentWriter = this.documentBuilder.parse(RECORDED_DATA);
}
} catch (Exception e) {
System.out.println("Error when creating DataRecorder: Document Writer");
}
Element root;
if (!tempFile.exists()) {
//Creates new Document if it doesnt exist
root = this.documentWriter.createElement("recordedData");
this.documentWriter.appendChild(root);
} else {
root = this.documentWriter.getDocumentElement();
}
Element player = this.documentWriter.createElement("Player");
player.setAttribute("name", this.username);
root.appendChild(player);
this.eventList = this.documentWriter.createElement("EventList");
this.eventList.setAttribute("date", Date.from(java.time.ZonedDateTime.now().toInstant()).toString());
this.eventList.setAttribute("timezone", java.time.ZonedDateTime.now().getZone().toString());
player.appendChild(this.eventList);
DOMSource source = new DOMSource(this.documentWriter);
StreamResult result = new StreamResult(System.getProperty("user.dir") + "/src/main/resources/recordedData.xml");
try {
this.transformer.transform(source, result);
} catch (Exception e) {
System.out.println("Error when creating DataRecorder: Could not write System Name and Date");
System.out.println(e);
}
}
This creates an XML file that looks like this
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<recordedData>
<Player name="Name">
<EventList date="Wed Jun 24 21:34:46 CEST 2020" timezone="Europe/Berlin"/>
</Player>
</recordedData>
The problem is that when i execute this Class with its own Main it just adds some new Lines to (which is what i want it to do) while when executing with maven it completly rewrites the xml file.
The path you have is your resources folder, the resources folder is a maven convenience folder, that folder doesn't exist when you run maven build. The contents of that folder are copied to target/classes folder when maven build runs.
Try using a folder that is outside your source code repository
Having the filedrop already implemented in my code, I need to parse the xml file I drop in the main().
Main()
case "XML":
text.append("Processing file type XML: "+files[i].getCanonicalPath() + "\n" );
ReadXml read_xml = new ReadXml();
read_xml.read(files[i].getCanonicalPath(), text);
break;
ReadXml.java
public class ReadXml {
ProgramDocument programDocument = new ProgramDocument();
public void read(String FILE, javax.swing.JTextArea text ) {
try {
JAXBContext context = JAXBContext.newInstance(ProgramDocument.class);
Unmarshaller u = context.createUnmarshaller();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(FILE);
Object o = u.unmarshal( doc );
doc.getDocumentElement().normalize();
text.append("Account : " +doc.getElementsByTagName("Account").item(0));
}
catch(Exception e) {
text.append("XML file not parsed correctly.\n");
}
}
}
I am not able to print anything, and when I am, I see "NULL" or just empty row or some path#numbers
I am not a developer, I just need to try opening a xml a send contents to a DB, but this is too far already.
EDIT: added part of xml
<?xml version="1.0" encoding="UTF-8"?>
<ARRCD Version="48885" Release="38">
<Identification v="ORCOZIO"/>
<Version v="013"/>
<Account v="OCTO">
<Type v="MAJO"/>
<Date v="2016-05-14"/>
</AARCD>
There are no elements tagged "Account" in the element "Account".
What you want to read here are the Attributes of Account, not other elements.
Thus you should use eElement.getAttribute("v") if you want to read attribute v, not getElementsByTagName()
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.
I currently have an xml resource file that has XML inclusions.
stream = Main.class.getResourceAsStream("resource/Resource.xml");
within the xml file:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.w3.org/1999/xhtml"
xmlns:xi="http://www.w3.org/2001/XInclude">
<element />
<xi:include href="resource/1.xml"/>
</semantics>
However, after parsing Resource.xml, I get an error that the file being included does not exist.
After checking, it seems that the path was concatenated with the root directory of my project, however my problem is that the resource file 1.xml will be inside a jar file later on.
Is it possible to make the DocumentBuilder to load inclusion as a reasource as well?
You need to set a custom EnitityResolver2 on your DocumentBuilder so that you can return the correct InputSource when then xi:include is processed.
final DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
documentBuilder.setEntityResolver(new EntityResolver2() {
#Override
public InputSource getExternalSubset(String string, String string1) throws SAXException, IOException {
return null;
}
#Override
public InputSource resolveEntity(String string, String string1, String string2, String string3) throws SAXException, IOException {
final String resourceName = string3;
final InputSource is = new InputSource();
is.setSystemId(resourceName);
is.setByteStream(Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName));
return is;
}
#Override
public InputSource resolveEntity(String string, String string1) throws SAXException, IOException {
return null;
}
});
This will now return an InputSource of the InputStream of the resource as loaded by the classloader. You may need to manipulate the String to get the right path.
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);