如何用JAXB创建Cell类映射XML元素、属性或仅文本值?
解决JAXB中Cell类支持两种XML结构的问题
嘿,这个JAXB的问题我刚好碰到过,给你捋捋怎么解决!首先得说清楚为啥你之前的写法不行:JAXB确实不允许在同一个类里同时用@XmlValue和@XmlElement(除非用@XmlMixed处理混合内容,但你之前没配置对)。要实现你要的两种<cell>标签结构,正确的做法是用@XmlMixed结合@XmlElement定义混合内容,同时保留@XmlAttribute处理display属性。
正确的Cell类实现
import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.*; import javax.xml.namespace.QName; import java.util.List; public class Cell { private String display; private List<Object> content; @XmlAttribute public String getDisplay() { return display; } public void setDisplay(String display) { this.display = display; } @XmlMixed @XmlElement(name = "text", type = String.class) public List<Object> getContent() { return content; } public void setContent(List<Object> content) { this.content = content; } // 工具方法:快速创建带<text>子元素的Cell public static Cell withTextElement(String textContent, String display) { Cell cell = new Cell(); cell.setDisplay(display); JAXBElement<String> textElement = new JAXBElement<>( new QName("text"), String.class, textContent ); cell.setContent(List.of(textElement)); return cell; } // 工具方法:快速创建带纯文本内容的Cell public static Cell withPlainText(String plainText) { return withPlainText(plainText, null); } public static Cell withPlainText(String plainText, String display) { Cell cell = new Cell(); cell.setDisplay(display); cell.setContent(List.of(plainText)); return cell; } }
配套的Page类
因为你的Cell标签是作为Page的子元素列表存在的,所以Page类要这么写:
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.util.List; @XmlRootElement(name = "Page") public class Page { private List<Cell> cells; @XmlElement(name = "cell") public List<Cell> getCells() { return cells; } public void setCells(List<Cell> cells) { this.cells = cells; } }
代码解释
@XmlMixed:这个注解告诉JAXB,当前类的内容可以是纯文本和子元素的混合,完美适配你需要的两种<cell>结构。@XmlElement(name = "text"):指定子元素名称为<text>,当content列表里放JAXBElement<String>对象时,JAXB会生成<text>...</text>子元素;如果放普通String,就直接生成纯文本内容。@XmlAttribute:用来映射display属性,两种<cell>结构都可以带这个属性(不带的话设为null即可)。
测试生成XML
用下面的代码可以生成你给出的示例XML结构:
import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import java.util.List; public class Main { public static void main(String[] args) throws Exception { JAXBContext context = JAXBContext.newInstance(Page.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Page page = new Page(); page.setCells(List.of( Cell.withTextElement("thisIsText1", "a"), Cell.withTextElement("thisIsText2", "b"), Cell.withTextElement("thisIsText3", "c"), Cell.withPlainText("value1"), Cell.withPlainText("value2"), Cell.withPlainText("value3") )); marshaller.marshal(page, System.out); } }
运行后输出的XML就是你要的:
<Page> <cell display="a"> <text>thisIsText1</text> </cell> <cell display="b"> <text>thisIsText2</text> </cell> <cell display="c"> <text>thisIsText3</text> </cell> <cell>value1</cell> <cell>value2</cell> <cell>value3</cell> </Page>
解析时的处理
如果要解析这种XML,拿到Cell对象后,可以通过判断content列表里的元素类型区分纯文本和<text>子元素:
for (Object item : cell.getContent()) { if (item instanceof String) { // 纯文本内容 String plainText = (String) item; System.out.println("Plain text: " + plainText); } else if (item instanceof JAXBElement) { // <text>子元素的内容 JAXBElement<String> textElement = (JAXBElement<String>) item; System.out.println("Text element content: " + textElement.getValue()); } }
内容的提问来源于stack exchange,提问作者JoeWill
相关产品推荐
相关产品推荐

