如何解决Java XML-在新元素内添加现有元素
我是Java的新手,正在研究XML文件。跳到这个问题,我必须如下修改给定的XML。
给出XML:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Elements>
<Item>
<Element>
<Value>On</Value>
</Element>
</Item>
<Item>
<Element>
<Value>On</Value>
</Element>
</Item>
</Elements>
已修改:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Elements>
<Entry>
<Item>
<Element>
<Value>On</Value>
</Element>
</Item>
</Entry>
<Entry>
<Item>
<Element>
<Value>On</Value>
</Element>
</Item>
</Entry>
</Elements>
我只需要创建一个新元素“ Entry”并剪切粘贴已经存在的“ Item”。我该如何实现?
解决方法
到目前为止,最简单的方法是使用XSLT样式表。
String xslt =
"<Elements xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xsl:version='1.0'>" +
" <xsl:for-each select='//Item'>" +
" <Entry><xsl:copy-of select='.'/></Entry>" +
" </xsl:for-each>" +
"</Elements>";
TransformerFactory factory = TransformerFactory.newInstance();
Transformer trans = factory.newTransformer(
new StreamSource(new StringReader(xslt)));
trans.transform(new StreamSource(inputFile),new StreamResult(outputFile));
,
以下是使用DOM和STAX映射XML的示例。当XML大小较小时,可以使用DOM,它将整个XML加载到内存中并提供对树中每个元素的访问。 STAX是基于事件的解析器,可用于非常大的XML文档。两者都是低级XML处理库。
变量xml
是源XML的字符串表示形式,代码中省略了它。
public static void main(String[] args) throws Exception {
// parse and map XML using DOM
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(xml)));
doc = map(doc);
System.out.println(serialize(doc));
// parse and map XML using STAX
InputStream is = new ByteArrayInputStream(xml.getBytes());
ByteArrayOutputStream os = map(is);
System.out.println(os.toString(StandardCharsets.UTF_8));
}
/**
* Uses DOM tree,iterating over item elements.
* For each item element detaches it,creates new entry element,attaches
* detached item element to it and inserts entry element into DOM.
*/
public static Document map(Document doc) {
NodeList nodes = doc.getDocumentElement().getElementsByTagName("Item");
for (int i = 0; i < nodes.getLength(); i++) {
Node child = nodes.item(i);
child = doc.getDocumentElement().removeChild(child);
Element entry = doc.createElement("Entry");
doc.adoptNode(entry);
doc.getDocumentElement().insertBefore(entry,doc.getDocumentElement().getFirstChild());
entry.appendChild(child);
}
return doc;
}
/**
* Uses STaX,event based parser.
* When handling parser events checks for item start- and end- events and
* adds appropriate entry element event before or after original event.
*/
public static ByteArrayOutputStream map(InputStream is) throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(is);
XMLEventWriter writer = XMLOutputFactory.newInstance().createXMLEventWriter(os);
XMLEventFactory ef = XMLEventFactory.newInstance();
while(reader.hasNext()) {
XMLEvent event = reader.nextEvent();
if(event.isStartElement() && event.asStartElement().getName().getLocalPart().equals("Item")) {
XMLEvent entryEvent = ef.createStartElement("",null,"Entry");
writer.add(entryEvent);
}
writer.add(event);
if(event.isEndElement() && event.asEndElement().getName().getLocalPart().equals("Item")) {
XMLEvent entryEvent = ef.createEndElement("","Entry");
writer.add(entryEvent);
}
}
return os;
}
/**
* Serializes DOM
*/
private static String serialize(Document document) {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
removeWhitespaces(document.getDocumentElement());
try (StringWriter writer = new StringWriter()) {
StreamResult result = new StreamResult(writer);
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD,"xml");
transformer.setOutputProperty(OutputKeys.INDENT,"yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount","4");
transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
transformer.transform(new DOMSource(document),result);
return writer.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Removes whitespace nodes from DOM
*/
private static void removeWhitespaces(Element element) {
NodeList children = element.getChildNodes();
for (int i = children.getLength() - 1; i >= 0; i--) {
Node child = children.item(i);
if (child instanceof Text && ((Text) child).getData().trim().isEmpty()) {
element.removeChild(child);
} else if (child instanceof Element) {
removeWhitespaces((Element) child);
}
}
}
,
使用Jackson
库,您可以将整个XML
有效负载读取为List<Map>
并编写自定义序列化程序,它将以新格式进行写入。参见以下示例:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializable;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import javax.xml.namespace.QName;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class XmlMapperApp {
public static void main(String... args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
XmlMapper mapper = XmlMapper.xmlBuilder()
.enable(SerializationFeature.INDENT_OUTPUT)
.enable(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)
.build();
List<Map<String,Object>> items = readOldXmlFormat(xmlFile,mapper);
String xml = writeNewXmlFormat(mapper,items);
System.out.println(xml);
}
private static List<Map<String,Object>> readOldXmlFormat(File xmlFile,XmlMapper mapper) throws IOException {
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class,Map.class);
return mapper.readValue(xmlFile,collectionType);
}
private static String writeNewXmlFormat(XmlMapper mapper,List<Map<String,Object>> items) throws IOException {
return mapper.writeValueAsString(new SerializableItems(items));
}
}
@JacksonXmlRootElement(localName = "Elements")
class SerializableItems implements JsonSerializable {
private final List<Map<String,Object>> items;
SerializableItems(List<Map<String,Object>> items) {
this.items = items;
}
private final QName itemQName = new QName("Item");
private final QName elementQName = new QName("Element");
private final QName entryQName = new QName("Entry");
@Override
public void serialize(JsonGenerator gen,SerializerProvider serializers) throws IOException {
ToXmlGenerator xmlGen = (ToXmlGenerator) gen;
xmlGen.writeStartObject();
for (Map<String,Object> item : items) {
xmlGen.startWrappedValue(entryQName,itemQName);
xmlGen.startWrappedValue(itemQName,elementQName);
for (Map.Entry<String,Object> entry : item.entrySet()) {
xmlGen.writeObjectField(entry.getKey(),entry.getValue());
}
xmlGen.finishWrappedValue(itemQName,elementQName);
xmlGen.finishWrappedValue(entryQName,itemQName);
}
xmlGen.writeEndObject();
}
@Override
public void serializeWithType(JsonGenerator gen,SerializerProvider serializers,TypeSerializer typeSer) throws IOException {
}
}
上面的代码打印:
<?xml version='1.0' encoding='UTF-8'?>
<Elements>
<Entry>
<Item>
<Element>
<Value>On</Value>
</Element>
</Item>
</Entry>
<Entry>
<Item>
<Element>
<Value>On</Value>
</Element>
</Item>
</Entry>
</Elements>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。