使用 StAX 简单修改 XML
Simple modification of XML with StAX
我正在尝试修改现有的 XML 文件。据我所知,不可能直接即时完成,所以我的想法是读取流中的文件,修改它,创建一个新文件,然后用新文件替换旧文件。
我只需要应用简单的更改,所以我决定采用 StAX 方法,因为它更适合大量数据或简单处理。
现有 XML 文件:
<?xml version='1.0' encoding='UTF-8'?>
<Company>
<Employee>
<FirstName>Tanmay</FirstName>
<LastName>Patil</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Bangalore</City>
<State>Karnataka</State>
<Zip>560212</Zip>
</Address>
</Employee>
</Company>
期望的输出:
<?xml version='1.0' encoding='UTF-8'?>
<Company>
<Employee>
<FirstName>Tanmay</FirstName>
<LastName>Patil</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Bangalore</City>
<State>Karnataka</State>
<NewElem>Some value</NewElem> <!-- Replacing all ZIP-elements -->
</Address>
</Employee>
</Company>
这段代码简单地复制了一个 XML 文件 (source):
public static void writeAll(XMLStreamReader xmlr, XMLStreamWriter writer)
throws XMLStreamException {
while (xmlr.hasNext()) {
write(xmlr, writer);
xmlr.next();
}
write(xmlr, writer); // write the last element
writer.flush();
}
public static void write(XMLStreamReader xmlr, XMLStreamWriter writer) throws XMLStreamException {
switch (xmlr.getEventType()) {
case XMLEvent.START_ELEMENT:
final String localName = xmlr.getLocalName();
final String namespaceURI = xmlr.getNamespaceURI();
if (namespaceURI != null && namespaceURI.length() > 0) {
final String prefix = xmlr.getPrefix();
if (prefix != null) {
writer.writeStartElement(prefix, localName, namespaceURI);
} else {
writer.writeStartElement(namespaceURI, localName);
}
} else {
writer.writeStartElement(localName);
}
for (int i = 0, len = xmlr.getNamespaceCount(); i < len; i++) {
writer.writeNamespace(xmlr.getNamespacePrefix(i), xmlr.getNamespaceURI(i));
}
for (int i = 0, len = xmlr.getAttributeCount(); i < len; i++) {
String attUri = xmlr.getAttributeNamespace(i);
if (attUri != null) {
writer.writeAttribute(attUri, xmlr.getAttributeLocalName(i), xmlr.getAttributeValue(i));
} else {
writer.writeAttribute(xmlr.getAttributeLocalName(i), xmlr.getAttributeValue(i));
}
}
break;
case XMLEvent.END_ELEMENT:
writer.writeEndElement();
break;
case XMLEvent.SPACE:
case XMLEvent.CHARACTERS:
writer.writeCharacters(xmlr.getTextCharacters(), xmlr.getTextStart(), xmlr.getTextLength());
break;
case XMLEvent.PROCESSING_INSTRUCTION:
writer.writeProcessingInstruction(xmlr.getPITarget(), xmlr.getPIData());
break;
case XMLEvent.CDATA:
writer.writeCData(xmlr.getText());
break;
case XMLEvent.COMMENT:
writer.writeComment(xmlr.getText());
break;
case XMLEvent.ENTITY_REFERENCE:
writer.writeEntityRef(xmlr.getLocalName());
break;
case XMLEvent.START_DOCUMENT:
String encoding = xmlr.getCharacterEncodingScheme();
String version = xmlr.getVersion();
if (encoding != null && version != null) {
writer.writeStartDocument(encoding, version);
} else if (version != null) {
writer.writeStartDocument(xmlr.getVersion());
}
break;
case XMLEvent.END_DOCUMENT:
writer.writeEndDocument();
break;
case XMLEvent.DTD:
writer.writeDTD(xmlr.getText());
break;
}
}
它有效,但我不确定 write()-method
的复杂性。那些开关盒真的有必要吗?
我也遇到了问题,将 ZIP 元素替换为
while (reader.hasNext()) {
write(reader, writer);
reader.next();
if (reader.getEventType() == XMLStreamReader.START_ELEMENT) {
String elementName = reader.getLocalName();
if (elementName.contains("ZIP")) {
writer.writeStartElement("newElem");
writer.writeAttribute("atr", "val");
writer.writeEndElement();
}
}
}
替换 XML 文件中的某些节点的最有效方法是什么?
XSLT 具有所谓的身份转换模式。
有用link:XSL Identity Transforms
下面的 XSLT 将按原样复制整个输入 XML,Zip 元素除外。一旦找到 Zip 元素,它将被替换为所需的新标签。
您只需从 Java 代码中调用 XSLT 转换即可。
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<Company>
<Employee>
<FirstName>Tanmay</FirstName>
<LastName>Patil</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Bangalore</City>
<State>Karnataka</State>
<Zip>560212</Zip>
</Address>
</Employee>
</Company>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" encoding="utf-8"/>
<!-- IdentityTransform -->
<xsl:template match="/ | @* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Zip">
<NewElem>Some value</NewElem>
</xsl:template>
</xsl:stylesheet>
Output XML
<?xml version='1.0' encoding='utf-8' ?>
<Company>
<Employee>
<FirstName>Tanmay</FirstName>
<LastName>Patil</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Bangalore</City>
<State>Karnataka</State>
<NewElem>Some value</NewElem>
</Address>
</Employee>
</Company>
我正在尝试修改现有的 XML 文件。据我所知,不可能直接即时完成,所以我的想法是读取流中的文件,修改它,创建一个新文件,然后用新文件替换旧文件。
我只需要应用简单的更改,所以我决定采用 StAX 方法,因为它更适合大量数据或简单处理。
现有 XML 文件:
<?xml version='1.0' encoding='UTF-8'?>
<Company>
<Employee>
<FirstName>Tanmay</FirstName>
<LastName>Patil</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Bangalore</City>
<State>Karnataka</State>
<Zip>560212</Zip>
</Address>
</Employee>
</Company>
期望的输出:
<?xml version='1.0' encoding='UTF-8'?>
<Company>
<Employee>
<FirstName>Tanmay</FirstName>
<LastName>Patil</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Bangalore</City>
<State>Karnataka</State>
<NewElem>Some value</NewElem> <!-- Replacing all ZIP-elements -->
</Address>
</Employee>
</Company>
这段代码简单地复制了一个 XML 文件 (source):
public static void writeAll(XMLStreamReader xmlr, XMLStreamWriter writer)
throws XMLStreamException {
while (xmlr.hasNext()) {
write(xmlr, writer);
xmlr.next();
}
write(xmlr, writer); // write the last element
writer.flush();
}
public static void write(XMLStreamReader xmlr, XMLStreamWriter writer) throws XMLStreamException {
switch (xmlr.getEventType()) {
case XMLEvent.START_ELEMENT:
final String localName = xmlr.getLocalName();
final String namespaceURI = xmlr.getNamespaceURI();
if (namespaceURI != null && namespaceURI.length() > 0) {
final String prefix = xmlr.getPrefix();
if (prefix != null) {
writer.writeStartElement(prefix, localName, namespaceURI);
} else {
writer.writeStartElement(namespaceURI, localName);
}
} else {
writer.writeStartElement(localName);
}
for (int i = 0, len = xmlr.getNamespaceCount(); i < len; i++) {
writer.writeNamespace(xmlr.getNamespacePrefix(i), xmlr.getNamespaceURI(i));
}
for (int i = 0, len = xmlr.getAttributeCount(); i < len; i++) {
String attUri = xmlr.getAttributeNamespace(i);
if (attUri != null) {
writer.writeAttribute(attUri, xmlr.getAttributeLocalName(i), xmlr.getAttributeValue(i));
} else {
writer.writeAttribute(xmlr.getAttributeLocalName(i), xmlr.getAttributeValue(i));
}
}
break;
case XMLEvent.END_ELEMENT:
writer.writeEndElement();
break;
case XMLEvent.SPACE:
case XMLEvent.CHARACTERS:
writer.writeCharacters(xmlr.getTextCharacters(), xmlr.getTextStart(), xmlr.getTextLength());
break;
case XMLEvent.PROCESSING_INSTRUCTION:
writer.writeProcessingInstruction(xmlr.getPITarget(), xmlr.getPIData());
break;
case XMLEvent.CDATA:
writer.writeCData(xmlr.getText());
break;
case XMLEvent.COMMENT:
writer.writeComment(xmlr.getText());
break;
case XMLEvent.ENTITY_REFERENCE:
writer.writeEntityRef(xmlr.getLocalName());
break;
case XMLEvent.START_DOCUMENT:
String encoding = xmlr.getCharacterEncodingScheme();
String version = xmlr.getVersion();
if (encoding != null && version != null) {
writer.writeStartDocument(encoding, version);
} else if (version != null) {
writer.writeStartDocument(xmlr.getVersion());
}
break;
case XMLEvent.END_DOCUMENT:
writer.writeEndDocument();
break;
case XMLEvent.DTD:
writer.writeDTD(xmlr.getText());
break;
}
}
它有效,但我不确定 write()-method
的复杂性。那些开关盒真的有必要吗?
我也遇到了问题,将 ZIP 元素替换为
while (reader.hasNext()) {
write(reader, writer);
reader.next();
if (reader.getEventType() == XMLStreamReader.START_ELEMENT) {
String elementName = reader.getLocalName();
if (elementName.contains("ZIP")) {
writer.writeStartElement("newElem");
writer.writeAttribute("atr", "val");
writer.writeEndElement();
}
}
}
替换 XML 文件中的某些节点的最有效方法是什么?
XSLT 具有所谓的身份转换模式。
有用link:XSL Identity Transforms
下面的 XSLT 将按原样复制整个输入 XML,Zip 元素除外。一旦找到 Zip 元素,它将被替换为所需的新标签。
您只需从 Java 代码中调用 XSLT 转换即可。
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<Company>
<Employee>
<FirstName>Tanmay</FirstName>
<LastName>Patil</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Bangalore</City>
<State>Karnataka</State>
<Zip>560212</Zip>
</Address>
</Employee>
</Company>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" encoding="utf-8"/>
<!-- IdentityTransform -->
<xsl:template match="/ | @* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Zip">
<NewElem>Some value</NewElem>
</xsl:template>
</xsl:stylesheet>
Output XML
<?xml version='1.0' encoding='utf-8' ?>
<Company>
<Employee>
<FirstName>Tanmay</FirstName>
<LastName>Patil</LastName>
<ContactNo>1234567890</ContactNo>
<Address>
<City>Bangalore</City>
<State>Karnataka</State>
<NewElem>Some value</NewElem>
</Address>
</Employee>
</Company>