I have to modify some attributes in an XML file with Java.
The input XML has all attribute values surrounded with single quotes.
But after making all the changes in the document, when I save the document into a XML file all the attribute values are surrounded by double quotes.
XMLOutputter xmlOutput = new XMLOutputter();
xmlOutput.output(doc, new FileWriter(path));
Is there any way that I can make the outputter use single quotes??
Thanks
Technically, yes.... but.... There is nothing semantically different between single and double quotes.... (the resulting document from JDOM is just as valid).... Is there a really good reason why you need to do this? If there is, I would be interested to know, and perhaps introduce it as a 'native' feature of JDOM....
But, you can change the format of it with (only) a little bit of work - 15 lines of code or so... The JDOM2 API in theory makes this a fair amount easier. You can create your own XMLOutputProcessor, using a subclass of the AbstractXMLOutputProcessor and override the printAttribute() method... for example (getting rid of some code paths that your are not likely to need (like non-escaped output):
private static final XMLOutputProcessor CUSTOMATTRIBUTEQUOTES = new AbstractXMLOutputProcessor() {
#Override
protected void printAttribute(final Writer out, final FormatStack fstack,
final Attribute attribute) throws IOException {
if (!attribute.isSpecified() && fstack.isSpecifiedAttributesOnly()) {
return;
}
write(out, " ");
write(out, attribute.getQualifiedName());
write(out, "=");
write(out, "'"); // Changed from "\""
// JDOM Code used to do this:
// attributeEscapedEntitiesFilter(out, fstack, attribute.getValue());
// Now we instead change to quoting the ' instead of "
String value = Format.escapeAttribute(fstack.getEscapeStrategy(), value);
// undo any " escaping that the Format may have done.
value = value.replaceAll(""", "\"");
// do any ' escaping that needs to be done.
value = value.replaceAll("'", "'");
write(out, value);
write(out, "'"); // Changed from "\""
}
};
Now that you have this cusome outputter, you can use it like:
XMLOutputter xmlOutput = new XMLOutputter(CUSTOMATTRIBUTEQUOTES);
xmlOutput.output(doc, new FileWriter(path));
Related
Using jcsv I'm trying to parse a CSV to a specified type. When I parse it, it says length of the data param is 1. This is incorrect. I tried removing line breaks, but it still says 1. Am I just missing something in plain sight?
This is my input string csvString variable
"Symbol","Last","Chg(%)","Vol",
INTC,23.90,1.06,28419200,
GE,26.83,0.19,22707700,
PFE,31.88,-0.03,17036200,
MRK,49.83,0.50,11565500,
T,35.41,0.37,11471300,
This is the Parser
public class BuySignalParser implements CSVEntryParser<BuySignal> {
#Override
public BuySignal parseEntry(String... data) {
// console says "Length 1"
System.out.println("Length " + data.length);
if (data.length != 4) {
throw new IllegalArgumentException("data is not a valid BuySignal record");
}
String symbol = data[0];
double last = Double.parseDouble(data[1]);
double change = Double.parseDouble(data[2]);
double volume = Double.parseDouble(data[3]);
return new BuySignal(symbol, last, change, volume);
}
}
And this is where I use the parser (right from the example)
CSVReader<BuySignal> cReader = new CSVReaderBuilder<BuySignal>(new StringReader( csvString)).entryParser(new BuySignalParser()).build();
List<BuySignal> signals = cReader.readAll();
jcsv allows different delimiter characters. The default is semicolon. Use CSVStrategy.UK_DEFAULT to get to use commas.
Also, you have four commas, and that usually indicates five values. You might want to remove the delimiters off the end.
I don't know how to make jcsv ignore the first line
I typically use CSVHelper to parse CSV files, and while jcsv seems pretty good, here is how you would do it with CVSHelper:
Reader reader = new InputStreamReader(new FileInputStream("persons.csv"), "UTF-8");
//bring in the first line with the headers if you want them
List<String> firstRow = CSVHelper.parseLine(reader);
List<String> dataRow = CSVHelper.parseLine(reader);
while (dataRow!=null) {
...put your code here to construct your objects from the strings
dataRow = CSVHelper.parseLine(reader);
}
You shouldn't have commas at the end of lines. Generally there are cell delimiters (commas) and line delimiters (newlines). By placing commas at the end of the line it looks like the entire file is one long line.
For some reason I have tried to surround the parameters sExtraParameter, sExtraParameter2, sExtraParameter3 with <![CDATA[ ]]> string in order to get "pretty-printed" latin characters. But every time I check the xml output, it stills show bad parsed characters.
So, if is there another way to apply the CDATA to this parameters?
public static Element xslTransformJDOM(File xmlFile, String xslStyleSheet, String sExtraParameter, String sExtraParameterValue, String sExtraParameter2, String sExtraParameterValue2, String sExtraParameter3,String sExtraParameterValue3 ) throws JDOMException, TransformerConfigurationException, FileNotFoundException, IOException{
try{
Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(xslStyleSheet));
transformer.setParameter(sExtraParameter, sExtraParameterValue);
transformer.setParameter(sExtraParameter2, sExtraParameterValue2);
transformer.setParameter(sExtraParameter3, sExtraParameterValue3);
JDOMResult out = new JDOMResult();
transformer.transform(new StreamSource(xmlFile), out);
Element result = out.getDocument().detachRootElement();
setSize(new XMLOutputter().outputString(result).length());
return result;
}
catch (TransformerException e){
throw new JDOMException("XSLT Transformation failed", e);
}
}
edit:
I am following up a project from my boss, for these reason I have not the entire code to show you here.
Maybe I have missed the question, but the API (http://docs.oracle.com/javaee/1.4/api/javax/xml/transform/Transformer.html#setParameter(java.lang.String, java.lang.Object)) for setParameter does not expect
value - The value object. This can be any valid Java object. It is up to the processor to provide the proper object coersion or to simply pass the object on for use in an extension.
This could then vary by implementation, assuming you are using JDOM.
There may be a CDATA xml element that would then be processed correctly. Maybe: http://www.jdom.org/docs/apidocs/org/jdom2/CDATA.html
You could still think about setting the serializer settings to some sort of whitespace preservation. http://www.jdom.org/docs/apidocs.1.1/org/jdom/output/Format.TextMode.html
I am developing an desktop application which reads specific XML Elements using XPath and displays them in text fields in a JFrame.
So far, the program ran smoothly until I decided to pass a String variable in the File class.
public void openNewFile(String filePath) {
//file path C:\\Documents and Settings\\tanzim.hasan\\my documents\\xcbl.XML
//is passed as a string from another class.
String aPath = filePath;
//Path is printed on screen before entering the try & catch.
System.out.println("File Path Before Try & Catch: "+filePath);
try {
//The following statement works if the file path is manually written.
// File xmlFile = new File ("C:\\Documents and Settings\\tanzim.hasan\\my documents\\xcbl.XML");
//The following statement prints the actual path
File xmlFile = new File(aPath);
System.out.println("file =" + xmlFile);
//From here the document does not print the expected results.
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
docFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
XPath srcPath = XPathFactory.newInstance().newXPath();
XPathShipToAddress shipToPath = new XPathShipToAddress(srcPath, doc);
XPathBuyerPartyAddress buyerPartyPath = new XPathBuyerPartyAddress(srcPath, doc);
} catch (Exception e) {
//
}
}
If I define the xmlFile with a static path (i.e. manually write it) then the program works as expected. However, instead of writing a static path, if I pass the path as a string variable aPath it does not print the expected results.
I have done a bit of googling but failed to find anything concrete.
Just use the builtin object methods:
System.out.println("file = "+xmlFile.toString());
You could also use:
System.out.println("f = " + f.getAbsolutePath());
Also, if you're having issues wit hthe file not existing, check first then proceed:
File file = new File (aPath);
if(file.exists()) {
//Do your work
}
If you are using replaceAll() like this path.replaceAll("\\", "/") to remove the backslashes, it will fail because the replaceAll() method expects a regex as the first parameter and a single backslash (coded as "\\") is an invalid regex. To make it work using replaceAll(), you would need double-escape the backslash (once for the String, again for the regex) like this path.replaceAll("\\\\", "/").
However, you don't need a regex! Instead, use the plain-text based replace() method like this:
path.replace("\\", "/")
Note that the names "replace" and "replaceAll" are misleading: "replace" still replaces all occurrences... the moron that decided on the name "replaceAll" should have chosen "replaceRegex" or something similar
Edit
Try:
path = path.replace("\\\\", "/");
it is too late to answer this but...removing "" from my config file helped
I mean
pathVariable=c:\\some\\path\\here
not this
pathVariable="c:\\some\\path\\here"
I have a program that loads lines from a user file, then selects the last part of the String (which would be an int)
Here's the style it's saved in:
nameOfValue = 0
nameOfValue2 = 0
and so on. I have selected the value for sure - I debugged it by printing. I just can't seem to save it back in.
if(nameOfValue.equals(type)) {
System.out.println(nameOfValue+" equals "+type);
value.replace(value, Integer.toString(Integer.parseInt(value)+1));
}
How would I resave it? I've tried bufferedwriter but it just erases everything in the file.
My suggestion is, save all the contents of the original file (either in memory or in a temporary file; I'll do it in memory) and then write it again, including the modifications. I believe this would work:
public static void replaceSelected(File file, String type) throws IOException {
// we need to store all the lines
List<String> lines = new ArrayList<String>();
// first, read the file and store the changes
BufferedReader in = new BufferedReader(new FileReader(file));
String line = in.readLine();
while (line != null) {
if (line.startsWith(type)) {
String sValue = line.substring(line.indexOf('=')+1).trim();
int nValue = Integer.parseInt(sValue);
line = type + " = " + (nValue+1);
}
lines.add(line);
line = in.readLine();
}
in.close();
// now, write the file again with the changes
PrintWriter out = new PrintWriter(file);
for (String l : lines)
out.println(l);
out.close();
}
And you'd call the method like this, providing the File you want to modify and the name of the value you want to select:
replaceSelected(new File("test.txt"), "nameOfValue2");
I think most convenient way is:
Read text file line by line using BufferedReader
For each line find the int part using regular expression and replace
it with your new value.
Create a new file with the newly created text lines.
Delete source file and rename your new created file.
Please let me know if you need the Java program implemented above algorithm.
Hard to answer without the complete code...
Is value a string ? If so the replace will create a new string but you are not saving this string anywhere. Remember Strings in Java are immutable.
You say you use a BufferedWriter, did you flush and close it ? This is often a cause of values mysteriously disappearing when they should be there. This exactly why Java has a finally keyword.
Also difficult to answer without more details on your problem, what exactly are you trying to acheive ? There may be simpler ways to do this that are already there.
currently i creating a java apps and no database required
that why i using text file to make it
the structure of file is like this
unique6id username identitynumber point
unique6id username identitynumber point
may i know how could i read and find match unique6id then update the correspond row of point ?
Sorry for lack of information
and here is the part i type is
public class Cust{
string name;
long idenid, uniqueid;
int pts;
customer(){}
customer(string n,long ide, long uni, int pt){
name = n;
idenid = ide;
uniqueid = uni;
pts = pt;
}
FileWriter fstream = new FileWriter("Data.txt", true);
BufferedWriter fbw = new BufferedWriter(fstream);
Cust newCust = new Cust();
newCust.name = memUNTF.getText();
newCust.ic = Long.parseLong(memICTF.getText());
newCust.uniqueID = Long.parseLong(memIDTF.getText());
newCust.pts= points;
fbw.write(newCust.name + " " + newCust.ic + " " + newCust.uniqueID + " " + newCust.point);
fbw.newLine();
fbw.close();
this is the way i text in the data
then the result inside Data.txt is
spencerlim 900419129876 448505 0
Eugene 900419081234 586026 0
when user type in 586026 then it will grab row of eugene
bind into Cust
and update the pts (0 in this case, try to update it into other number eg. 30)
Thx for reply =D
Reading is pretty easy, but updating a text file in-place (ie without rewriting the whole file) is very awkward.
So, you have two options:
Read the whole file, make your changes, and then write the whole file to disk, overwriting the old version; this is quite easy, and will be fast enough for small files, but is not a good idea for very large files.
Use a format that is not a simple text file. A database would be one option (and bear in mind that there is one, Derby, built into the JDK); there are other ways of keeping simple key-value stores on disk (like a HashMap, but in a file), but there's nothing built into the JDK.
You can use OpenCSV with custom separators.
Here's a sample method that updates the info for a specified user:
public static void updateUserInfo(
String userId, // user id
String[] values // new values
) throws IOException{
String fileName = "yourfile.txt.csv";
CSVReader reader = new CSVReader(new FileReader(fileName), ' ');
List<String[]> lines = reader.readAll();
Iterator<String[]> iterator = lines.iterator();
while(iterator.hasNext()){
String[] items = (String[]) iterator.next();
if(items[0].equals(userId)){
for(int i = 0; i < values.length; i++){
String value = values[i];
if(value!=null){
// for every array value that's not null,
// update the corresponding field
items[i+1]=value;
}
}
break;
}
}
new CSVWriter(new FileWriter(fileName), ' ').writeAll(lines);
}
Use InputStream(s) and Reader(s) to read file.
Here is a code snippet that shows how to read file.
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("c:/myfile.txt")));
String line = null;
while ((line = reader.readLine()) != null) {
// do something with the line.
}
Use OutputStream and Writer(s) to write to file. Although you can use random access files, i.e. write to the specific place of the file I do not recommend you to do this. Much easier and robust way is to create new file every time you have to write something. I know that it is probably not the most efficient way, but you do not want to use DB for some reasons... If you have to save and update partial information relatively often and perform search into the file I'd recommend you to use DB. There are very light weight implementations including pure java implementations (e.g. h2: http://www.h2database.com/html/main.html).