我看不出您为什么不满意将 xml 文档保存在内存中的原因,除非您正在使用的 xml 文件很大 (100+ MB)。
我可以想到两种方法来解决这个问题:
逐字符读取文件并更改需要更改的内容。这符合您的要求,但实施起来很慢且很难。
使用 xml 解析器,找到您要查找的元素并更改它们。我倾向于这个。
第一种方法是逐个字符地读取 xml 文件,找到您要查找的标签,更改它们并将 xml 写入第二个文件。这是非常流线型的,但是,它的 xml 可以在标签中包含标签,因此可以很快变得复杂。您可以使用解析器来实现这一点,但这可能需要将文档保存在内存中。
第二个很简单。使用 xml 解析器解析文件,遍历元素,更改它们,最后将编辑后的 xml 写回文件。这涉及将文档保存在内存中,但除非您使用内存受限的计算机或文档很大(100+ MB),否则这不是问题。
我不会在这里写出完整的程序,也不会给出第一种方式的示例(无论如何发布到SO都太复杂了),不过我会为您提供第二种方式的起点。
你来这里是为了什么:
使用 Java 8 更新 65 编写
需要库:Dom4J 用于 xml 解析器。
public class Main {
private static final Scanner SCANNER = new Scanner(System.in);
/**
* The file we're reading from.
*/
private File inputFile;
/**
* The file we're writing to.
*/
private File outputFile;
/**
* The attributes to replace.
*/
private List<UserAttribute> attributes = new ArrayList<>();
private Main() {
getFiles();
getReplacementTags();
}
private void getFiles() {
System.out.println("Please enter the input file...");
String input = SCANNER.nextLine();
File inFile = new File(input);
if (!inFile.exists() || !inFile.isFile()) {
System.err.println("The file you entered doesn't exits or isn't a file!");
System.exit(1);
}
inputFile = inFile;
System.out.println("Please enter the output file...");
String output = SCANNER.nextLine();
File outFile = new File(output);
if (!outFile.exists()) {
try {
outFile.createNewFile();
System.out.println("Created file: " + outFile);
} catch (IOException ex) {
System.err.println("Couldn't create the output file!");
System.exit(2);
}
}
outputFile = outFile;
}
private void getReplacementTags() {
System.out.println("Enter the tags you wish to replace");
System.out.println("The format is &element name &attribute &replacement. (e.g. &one &a att &UPDATED!)");
System.out.println("Enter a list of tags you wish to replace with each in a new line. Enter # when finished.");
while (true) {//I'm using an infinate loop because it just seams easier to implement.
String line = SCANNER.nextLine();
if (line.equals("#")) {
break;
}
try {
UserAttribute attribute = getAttributeFromUserText(line);
this.attributes.add(attribute);
System.out.println("Added attribute replacement: " + attribute);
} catch (IllegalArgumentException ex) {
System.err.println("Incorrect attribute format: \n\t" + ex.getMessage());
}
}
startReplacing();
}
private void startReplacing() {
@SuppressWarnings("UnusedAssignment")
Document doc = null;
try {
doc = new SAXReader().read(inputFile);
} catch (DocumentException ex) {
System.err.println("Coundn't read xml file: " + ex.getMessage());
System.exit(3);
}
replaceAttributes(doc);
try (FileWriter writer = new FileWriter(outputFile)) {
doc.write(writer);
System.out.println("Saved xml document to file: " + outputFile);
} catch (IOException ex) {
System.err.println("Couldn't write to file: " + ex.getMessage());
}
}
/**
* This does all the magic.
*
* You might want to fix this up as I'm sure it's rather slow. This only
* scans 1 tag deep.
*/
private void replaceAttributes(Document doc) {
for (UserAttribute uattribute : attributes) {
Element root = doc.getRootElement();
for (Iterator i = root.elementIterator(); i.hasNext();) {
Element element = (Element) i.next();
if (element.getName().equals(uattribute.element)) {
for (Iterator i1 = element.attributeIterator(); i1.hasNext();) {
Attribute attribute = (Attribute) i1.next();
if(attribute.getName().equals(uattribute.attribute)){
attribute.setValue(uattribute.replacement);
}
}
}
}
}
}
public static void main(String[] args) {
Main m = new Main();
}
private static UserAttribute getAttributeFromUserText(String text) throws IllegalArgumentException {//This is a bit incomplete...
String[] split = text.split("&");
if (split.length != 4) {
throw new IllegalArgumentException("Incorrect number of arguments!");
}
return new UserAttribute(split[1].replace(" ", ""), split[2].replace(" ", ""), split[3]);
}
private static final class UserAttribute {
public final String element;
public final String attribute;
public final String replacement;
public UserAttribute(String element, String attribute, String replacement) {
this.element = element;
this.attribute = attribute;
this.replacement = replacement;
}
public String getElement() {
return element;
}
public String getAttribute() {
return attribute;
}
public String getReplacement() {
return replacement;
}
@Override
public String toString() {
return String.format("{element=%s, attribute=%s, replacement=%s}", element, attribute, replacement);
}
}
}
A.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<PersonA name="Jenny" age="22">
<!-- A Random Comment -->
<friends number="3">
Friend A,
Friend B,
Friend C
</friends>
</PersonA>
<PersonB name="Bob" age="44">
<!-- A Random Comment... again -->
<friends number="5">
Friend A,
Friend B,
Friend C,
Friend D,
Friend E
</friends>
</PersonB>
</root>
B.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<PersonA name="Joe" age="41">
<!-- A Random Comment -->
<friends number="3">
Friend A,
Friend B,
Friend C
</friends>
</PersonA>
<PersonB name="Ashley" age="32">
<!-- A Random Comment... again -->
<friends number="5">
Friend A,
Friend B,
Friend C,
Friend D,
Friend E
</friends>
</PersonB>
</root>
参数
run:
Please enter the input file...
A.xml
Please enter the output file...
B.xml
Enter the tags you wish to replace
The format is &element name &attribute &replacement. (e.g. &one &a att &UPDATED!)
Enter a list of tags you wish to replace with each in a new line. Enter # when finished.
&PersonA &name &Joe
Added attribute replacement: {element=PersonA, attribute=name, replacement=Joe}
&PersonA &age &41
Added attribute replacement: {element=PersonA, attribute=age, replacement=41}
&PersonB &name &Ashley
Added attribute replacement: {element=PersonB, attribute=name, replacement=Ashley}
&PersonB &age &32
Added attribute replacement: {element=PersonB, attribute=age, replacement=32}
#
Saved xml document to file: B.xml
BUILD SUCCESSFUL (total time: 1 minute 32 seconds)
这几乎可以满足您的所有要求,唯一的问题是:
- 它有点慢,因为它必须扫描每个元素等等。
- 它只扫描顶级元素(即不会扫描朋友标签)
- 非常基础
尽管抛开问题不谈,但这应该能让你领先一步……我希望。
附:对于任何拼写错误,大字,格式不正确,我们深表歉意。我确实在短时间内写了这个,没有做太多的测试。如果您发现有问题,请发表评论。