Java:读取输入 xml 并使用一些更新的属性值写入输出 xml
Java: read input xml and write output xml with some updated attribute values
我必须读取一个大 xml 文件 (A.xml
) 并创建一个新的 xml 文件 (B.xml
),其内容与 A.xml
除了需要在B.xml
中更新的一些属性值。
例如,如果 A.xml
是:
<?xml version="1.0" encoding="utf-8"?>
<one>
<!-- comment -->
<a att="hello" />
</one>
<two />
我希望B.xml
包含:
<?xml version="1.0" encoding="utf-8"?>
<one>
<!-- comment -->
<a att="UPDATED" />
</one>
<two />
我在看one solution,它使用SAX进行解析,使用PrintWriter
进行编写,但它看起来很低级,我不知道是否可以复制注释并保留这种类型的关闭标签:/>
。
我更喜欢流式解析器,而不是将整个文档加载到内存中,但我愿意接受建议。
对于流式解决方案,您可以使用 javax.xml.stream.XMLStreamReader
或 XMLEventReader
来阅读 XML 文档,更新您想要更改的任何部分,并通过管道传输 data/events 从 reader 变成 javax.xml.stream.XMLStreamWriter
或 XMLEventWriter
.
我看不出您对将 xml 文档保存在内存中不满意的原因,除非您正在处理的 xml 文件很大(100+ MB ).
我可以想到两种方法来解决这个问题:
逐个字符读取文件并更改需要更改的内容。这符合您的要求,但实施起来速度慢且难以实施。
使用 xml 解析器,找到您要查找的元素并更改它们。我倾向于这个。
第一种方法是逐字符读取 xml 文件,找到您要查找的标签,更改它们并将 xml 写入第二个文件正在做这个。这非常流线型,但是,它 xml 可以在标签中包含标签,因此可以很快变得复杂。您可以使用解析器实现此目的,但这可能涉及将文档保存在内存中。
第二个很简单。使用 xml 解析器解析文件,遍历元素,更改它们,最后,将编辑后的 xml 写回文件。这涉及将文档保存在内存中,但除非您使用的是内存受限的计算机或文档很大(100+ MB),否则这不是真正的问题。
我不会在这里写出一个完整的程序,也不会给出第一种方式的例子(反正post到SO太复杂了),我给你一个起点第二种方式。
你来这里的目的:
写着Java8更新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)
这几乎可以满足您的所有要求,唯一的问题是:
- 它有点慢,因为它必须扫描每个元素等等。
- 它只扫描顶级元素(即不会扫描朋友标签)
- 非常基础
尽管抛开问题不谈,这应该能让您抢先一步……我希望如此。
P.S。对于任何拼写错误、错误、格式不正确,我们深表歉意。我确实在很短的时间内写了这篇文章,没有做太多测试。发现不对的请评论。
您的更新用例的最佳 XML 解析器无疑是 VTD-XML... 原因如下:
- 它的内存效率比 DOM 高得多...vtd-xml 的 1.3x ~ 1.5x
与 DOM
的 3x~5x 相比
- 支持增量更新,在所有可用的XML解析库中是独一无二的。基本上,你只需要将原来的属性值"hello"剪掉,然后用"UPDATE." 没有触及文档的其他部分...
阅读this paper了解更多信息:标题为“Processing XML with Java – A Performance Benchmark ".
我必须读取一个大 xml 文件 (A.xml
) 并创建一个新的 xml 文件 (B.xml
),其内容与 A.xml
除了需要在B.xml
中更新的一些属性值。
例如,如果 A.xml
是:
<?xml version="1.0" encoding="utf-8"?>
<one>
<!-- comment -->
<a att="hello" />
</one>
<two />
我希望B.xml
包含:
<?xml version="1.0" encoding="utf-8"?>
<one>
<!-- comment -->
<a att="UPDATED" />
</one>
<two />
我在看one solution,它使用SAX进行解析,使用PrintWriter
进行编写,但它看起来很低级,我不知道是否可以复制注释并保留这种类型的关闭标签:/>
。
我更喜欢流式解析器,而不是将整个文档加载到内存中,但我愿意接受建议。
对于流式解决方案,您可以使用 javax.xml.stream.XMLStreamReader
或 XMLEventReader
来阅读 XML 文档,更新您想要更改的任何部分,并通过管道传输 data/events 从 reader 变成 javax.xml.stream.XMLStreamWriter
或 XMLEventWriter
.
我看不出您对将 xml 文档保存在内存中不满意的原因,除非您正在处理的 xml 文件很大(100+ MB ).
我可以想到两种方法来解决这个问题:
逐个字符读取文件并更改需要更改的内容。这符合您的要求,但实施起来速度慢且难以实施。
使用 xml 解析器,找到您要查找的元素并更改它们。我倾向于这个。
第一种方法是逐字符读取 xml 文件,找到您要查找的标签,更改它们并将 xml 写入第二个文件正在做这个。这非常流线型,但是,它 xml 可以在标签中包含标签,因此可以很快变得复杂。您可以使用解析器实现此目的,但这可能涉及将文档保存在内存中。
第二个很简单。使用 xml 解析器解析文件,遍历元素,更改它们,最后,将编辑后的 xml 写回文件。这涉及将文档保存在内存中,但除非您使用的是内存受限的计算机或文档很大(100+ MB),否则这不是真正的问题。
我不会在这里写出一个完整的程序,也不会给出第一种方式的例子(反正post到SO太复杂了),我给你一个起点第二种方式。
你来这里的目的:
写着Java8更新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)
这几乎可以满足您的所有要求,唯一的问题是:
- 它有点慢,因为它必须扫描每个元素等等。
- 它只扫描顶级元素(即不会扫描朋友标签)
- 非常基础
尽管抛开问题不谈,这应该能让您抢先一步……我希望如此。
P.S。对于任何拼写错误、错误、格式不正确,我们深表歉意。我确实在很短的时间内写了这篇文章,没有做太多测试。发现不对的请评论。
您的更新用例的最佳 XML 解析器无疑是 VTD-XML... 原因如下:
- 它的内存效率比 DOM 高得多...vtd-xml 的 1.3x ~ 1.5x 与 DOM 的 3x~5x 相比
- 支持增量更新,在所有可用的XML解析库中是独一无二的。基本上,你只需要将原来的属性值"hello"剪掉,然后用"UPDATE." 没有触及文档的其他部分...
阅读this paper了解更多信息:标题为“Processing XML with Java – A Performance Benchmark ".