如何使用JAXB将XML文件的子部分解析为标签不含命名空间的原始XML字符串
如何使用JAXB将XML文件的子部分解析为标签不含命名空间的原始XML字符串
嘿,刚好我之前处理过一模一样的需求——用JAXB映射大部分XML节点到Java类,只把指定节点下的内容原封不动(带标签)转成字符串,还得去掉命名空间痕迹。下面给你详细说具体怎么实现:
第一步:定义Java实体类结构
首先我们要把XML里的非ItemDescription部分映射成常规的Java类,ItemDescription则单独做包装类,用来存kind属性和原始XML字符串:
1. 主实体类 Item
这个类对应XML根节点,映射ID和所有ItemDescription节点:
import javax.xml.bind.annotation.*; import java.util.List; @XmlRootElement(name = "Item", namespace = "http://www.example.com/item") @XmlAccessorType(XmlAccessType.FIELD) public class Item { private String ID; @XmlElement(name = "ItemDescription") private List<ItemDescriptionContent> itemDescriptions; // 别忘了生成getter和setter方法 }
2. ItemDescription包装类 ItemDescriptionContent
这里是关键,用@XmlAnyElement指定自定义的DomHandler,让JAXB把节点内容交给我们自己处理:
import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) public class ItemDescriptionContent { @XmlAttribute private String kind; // 用自定义DomHandler处理子节点,转成原始XML字符串 @XmlAnyElement(MyDomHandler.class) private String rawXmlContent; // getter和setter方法 }
第二步:实现自定义DomHandler处理节点转字符串(去命名空间)
核心逻辑就在这个DomHandler里,它负责把XML节点转换成字符串,同时移除所有命名空间相关的内容:
import org.w3c.dom.*; import javax.xml.bind.ValidationEventHandler; import javax.xml.bind.annotation.DomHandler; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.StringWriter; public class MyDomHandler implements DomHandler<String, StreamResult> { private StringWriter xmlWriter = new StringWriter(); @Override public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) { return new StreamResult(xmlWriter); } @Override public String getElement(StreamResult rt) { // 先拿到带命名空间的原始XML字符串 String rawXml = rt.getWriter().toString(); // 移除所有命名空间声明(比如xmlns="xxx") rawXml = rawXml.replaceAll(" xmlns(:\\w+)?=\"[^\"]*\"", ""); // 移除标签里的命名空间前缀(比如<ns0:p>变成<p>) rawXml = rawXml.replaceAll("<(/)?\\w+:", "<$1"); return rawXml.trim(); } @Override public Source marshal(String n, ValidationEventHandler errorHandler) { // 如果需要把字符串写回XML的话再完善这个方法,解析阶段可以先这么简单实现 try { DOMSource source = new DOMSource(); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.transform(new StreamResult(new StringReader(n)), new DOMResult(source.getNode())); return source; } catch (TransformerException e) { throw new RuntimeException("Failed to marshal raw XML", e); } } }
第三步:测试解析代码
最后写个测试类验证一下,把你的item.xml文件解析成Java对象,然后打印出ItemDescription的原始XML内容:
import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import java.io.File; public class JaxbParserTest { public static void main(String[] args) throws Exception { JAXBContext context = JAXBContext.newInstance(Item.class); Unmarshaller unmarshaller = context.createUnmarshaller(); Item item = (Item) unmarshaller.unmarshal(new File("item.xml")); // 遍历输出结果 for (ItemDescriptionContent desc : item.getItemDescriptions()) { System.out.println("Kind: " + desc.getKind()); System.out.println("Raw XML Content:\n" + desc.getRawXmlContent()); System.out.println("------------------------"); } } }
效果说明
运行测试代码后,你会得到这样的输出:
Kind: long Raw XML Content: <p> <u>This is a description</u> </p> <br/> <p>End Of description</p> ------------------------ Kind: short Raw XML Content: <p> <u>This is a description</u> </p> ------------------------
完全符合你的需求:其他节点正常映射Java类,ItemDescription下的所有内容(带标签)转成字符串,而且没有任何命名空间痕迹。
备注:内容来源于stack exchange,提问作者bloub
相关产品推荐
相关产品推荐

