对于超过 10000 条记录,如何更快地在 XML 节点中添加属性?(java)
How do I add attribute in XML node faster for more than 10000 record?(java)
我必须向具有超过 10k 记录的 XML 节点添加一个属性,所以什么是更快地转换 XML 文档的最佳方法。
我已经尝试过 StAX 解析器,添加属性几乎需要 4 分钟,而使用 SAX 解析器应该需要 5 分钟。
是否有任何其他可用的库可以做得更好或有其他方法可以做到这一点,请提出您的建议。
示例代码:(使用 STAX 解析器)
try {
XMLStreamReader r = factory.createXMLStreamReader(new FileInputStream(inputfile));
/* Start Writing document */
XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
XMLEventWriter xmlEventWriter = xmlOutputFactory.createXMLEventWriter(new FileOutputStream(outputfile),
"UTF-8");
/* End Writing document */
int event = r.getEventType();
long startTime = System.currentTimeMillis();
System.out.println("Started reading node from xml document....." + TimeUnit.MILLISECONDS.toSeconds(startTime));
int node1Cnt = 0, node2Cnt = 0, node3Cnt = 0, node4Cnt = 0;
while (true) {
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
switch (event) {
case XMLStreamConstants.START_DOCUMENT:
// System.out.println("Start Document.");
StartDocument startDocument = eventFactory.createStartDocument();
xmlEventWriter.add(startDocument);
break;
case XMLStreamConstants.START_ELEMENT:
// Create Start node
if (r.getLocalName().equalsIgnoreCase(node1)) {
node1Cnt++;
node2Cnt = 0;
Attribute attribute = eventFactory.createAttribute("id", "5522" + node1Cnt);
List attributeList = Arrays.asList(attribute);
List nsList = Arrays.asList();
StartElement sElement = eventFactory.createStartElement("", "", r.getLocalName(),attributeList.iterator(), nsList.iterator());
xmlEventWriter.add(sElement);
} else if (r.getLocalName().equalsIgnoreCase(node2Cnt)) {
node2Cnt++;
Attribute attribute = eventFactory.createAttribute("id", "5522" + node1Cnt + node2Cnt);
List attributeList = Arrays.asList(attribute);
List nsList = Arrays.asList();
StartElement sElement = eventFactory.createStartElement("", "", r.getLocalName(),
attributeList.iterator(), nsList.iterator());
xmlEventWriter.add(sElement);
} else {
StartElement sElement = eventFactory.createStartElement("", "", r.getLocalName());
xmlEventWriter.add(sElement);
}
StartElement sElement = eventFactory.createStartElement("", "", r.getLocalName());
xmlEventWriter.add(sElement);
break;
case XMLStreamConstants.CHARACTERS:
if (r.isWhiteSpace())
break; // System.out.println("Text: " + r.getText());
Characters characters = eventFactory.createCharacters(r.getText());
xmlEventWriter.add(characters);
break;
case XMLStreamConstants.END_ELEMENT:
// System.out.println("End Element:" + r.getName());
EndElement endElement = eventFactory.createEndElement("", "", r.getLocalName());
xmlEventWriter.add(endElement);
break;
case XMLStreamConstants.END_DOCUMENT:
xmlEventWriter.add(eventFactory.createEndDocument());
break;
}
if (!r.hasNext())
break;
event = r.next();
}
r.close();
System.out.println("Ended reading node from xml document....."
+ (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
- TimeUnit.MILLISECONDS.toSeconds(startTime)));
}catch(XMLStreamException ex){
ex.printStackTrace();
}catch(IOException ex){
// TODO Auto-generated catch block
ex.printStackTrace();
}finally{
System.out.println("finish!!");
}
我怀疑 XMLEventFactory.newInstance() 非常昂贵,因为它涉及到类路径的搜索。完全没有必要在事件循环中创建一个新的工厂:一开始就创建一个工厂并重复使用它。
除此之外,我怀疑使用 XMLStreamWriter 可能比使用 XMLEventWriter 更容易和更快。
(但是这些性能猜想是猜测,因为在调整性能时您总是需要进行测量以评估代码更改的影响。)
我个人会用 XSLT 编写。您没有提供足够的转换细节,但在 XSLT 3.0 中是这样的:
<xsl:transform....>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="node1">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:variable name="node1id" as="xs:string">
<xsl:text>5522</xsl:text>
<xsl:number/>
</xsl:variable>
<xsl:attribute name="id" select="$node1id"/>
<xsl:apply-templates>
<xsl:with-param name="node1id" select="$node1id" tunnel="yes"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="node2">
<xsl:param name="node1id" tunnel="yes"/>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="id">
<xsl:value-of select="$node1id"/>
<xsl:number/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:transform>
我必须向具有超过 10k 记录的 XML 节点添加一个属性,所以什么是更快地转换 XML 文档的最佳方法。
我已经尝试过 StAX 解析器,添加属性几乎需要 4 分钟,而使用 SAX 解析器应该需要 5 分钟。
是否有任何其他可用的库可以做得更好或有其他方法可以做到这一点,请提出您的建议。
示例代码:(使用 STAX 解析器)
try {
XMLStreamReader r = factory.createXMLStreamReader(new FileInputStream(inputfile));
/* Start Writing document */
XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
XMLEventWriter xmlEventWriter = xmlOutputFactory.createXMLEventWriter(new FileOutputStream(outputfile),
"UTF-8");
/* End Writing document */
int event = r.getEventType();
long startTime = System.currentTimeMillis();
System.out.println("Started reading node from xml document....." + TimeUnit.MILLISECONDS.toSeconds(startTime));
int node1Cnt = 0, node2Cnt = 0, node3Cnt = 0, node4Cnt = 0;
while (true) {
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
switch (event) {
case XMLStreamConstants.START_DOCUMENT:
// System.out.println("Start Document.");
StartDocument startDocument = eventFactory.createStartDocument();
xmlEventWriter.add(startDocument);
break;
case XMLStreamConstants.START_ELEMENT:
// Create Start node
if (r.getLocalName().equalsIgnoreCase(node1)) {
node1Cnt++;
node2Cnt = 0;
Attribute attribute = eventFactory.createAttribute("id", "5522" + node1Cnt);
List attributeList = Arrays.asList(attribute);
List nsList = Arrays.asList();
StartElement sElement = eventFactory.createStartElement("", "", r.getLocalName(),attributeList.iterator(), nsList.iterator());
xmlEventWriter.add(sElement);
} else if (r.getLocalName().equalsIgnoreCase(node2Cnt)) {
node2Cnt++;
Attribute attribute = eventFactory.createAttribute("id", "5522" + node1Cnt + node2Cnt);
List attributeList = Arrays.asList(attribute);
List nsList = Arrays.asList();
StartElement sElement = eventFactory.createStartElement("", "", r.getLocalName(),
attributeList.iterator(), nsList.iterator());
xmlEventWriter.add(sElement);
} else {
StartElement sElement = eventFactory.createStartElement("", "", r.getLocalName());
xmlEventWriter.add(sElement);
}
StartElement sElement = eventFactory.createStartElement("", "", r.getLocalName());
xmlEventWriter.add(sElement);
break;
case XMLStreamConstants.CHARACTERS:
if (r.isWhiteSpace())
break; // System.out.println("Text: " + r.getText());
Characters characters = eventFactory.createCharacters(r.getText());
xmlEventWriter.add(characters);
break;
case XMLStreamConstants.END_ELEMENT:
// System.out.println("End Element:" + r.getName());
EndElement endElement = eventFactory.createEndElement("", "", r.getLocalName());
xmlEventWriter.add(endElement);
break;
case XMLStreamConstants.END_DOCUMENT:
xmlEventWriter.add(eventFactory.createEndDocument());
break;
}
if (!r.hasNext())
break;
event = r.next();
}
r.close();
System.out.println("Ended reading node from xml document....."
+ (TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
- TimeUnit.MILLISECONDS.toSeconds(startTime)));
}catch(XMLStreamException ex){
ex.printStackTrace();
}catch(IOException ex){
// TODO Auto-generated catch block
ex.printStackTrace();
}finally{
System.out.println("finish!!");
}
我怀疑 XMLEventFactory.newInstance() 非常昂贵,因为它涉及到类路径的搜索。完全没有必要在事件循环中创建一个新的工厂:一开始就创建一个工厂并重复使用它。
除此之外,我怀疑使用 XMLStreamWriter 可能比使用 XMLEventWriter 更容易和更快。
(但是这些性能猜想是猜测,因为在调整性能时您总是需要进行测量以评估代码更改的影响。)
我个人会用 XSLT 编写。您没有提供足够的转换细节,但在 XSLT 3.0 中是这样的:
<xsl:transform....>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="node1">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:variable name="node1id" as="xs:string">
<xsl:text>5522</xsl:text>
<xsl:number/>
</xsl:variable>
<xsl:attribute name="id" select="$node1id"/>
<xsl:apply-templates>
<xsl:with-param name="node1id" select="$node1id" tunnel="yes"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="node2">
<xsl:param name="node1id" tunnel="yes"/>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="id">
<xsl:value-of select="$node1id"/>
<xsl:number/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:transform>