使用 JAXB 将两个同构 XML 模式解析为一个 class 结构
Parsing two isomorphous XML schemas into one class structure using JAXB
考虑两个同构 XML 模式。这里的同构是指这两个模式除了属性和标签名称之外具有相同的结构。更具体地说,我有一个活生生的例子,当是架构时,比如 A
,及其副本 B
,其中所有标签和属性名称都从英语翻译成等效的国家语言。
例如,作为输入,我们可以有一个对象的两个不同变体:
<tag_1_v1>
<tag_2_v1 id="blabla" name="xxxxx">
Some value1
</tag_2_v1>
<tag_3_v1 id="alalala" name="yyyyy">
Some value2
</tag_3_v1>
</tag_1_v1>
和
<tag_1_v2>
<tag_2_v2 special_id_2="blabla" name="xxxxx">
Some value1
</tag_2_v2>
<tag_3_v2 id="alalala" special_name_2="yyyyy">
Some value2
</tag_3_v2>
</tag_1_v2>
问题 是将这两个模式映射到单个 class 结构上,比方说
class Tag1 {
Tag2 tag2;
Tag3 tag3;
}
class Tag2 {
String id;
String name;
String value;
}
class Tag3 {
String id;
String name;
String value;
}
有多种解决此问题的想法,但所有想法都不是那么方便,因为在同一 class 结构上使用单个 JAXB 注释方案的可能性很大。他们是:
- 创建两个不同的 class 集,然后从对象中复制值
一个模式到另一个模式;
- 创建自己的 SAX 解析器实现并 "translate" 在其中将标签和属性名称转换为适当的名称;
- 使用 XML 自己的预处理器并使用字符串替换(如果 id 和属性名称在所有模式中不相同,则将不起作用)。
因为每个 <tag_i>
可以有不同的属性,一个干净的解决方案是使用继承:
- 创建一个由
Tag1V1
和 Tag1V2
继承的摘要 class Tag1
。将所有公共代码分解为 Tag1
.
Tag2
和 Tag3
也是如此。
为了让你开始,下面是 Tag2
:
的一个实现
@XmlRootElement
@XmlSeeAlso({Tag2V1.class, Tag2V2.class})
abstract class Tag2 {
private String name;
private String content;
@XmlAttribute(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlValue
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
@XmlRootElement(name = "tag_2_v1")
class Tag2V1 extends Tag2 {
private String id;
@XmlAttribute(name = "id")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
@XmlRootElement(name = "tag_2_v2")
class Tag2V2 extends Tag2 {
private String specialId2;
@XmlAttribute(name = "special_id_2")
public String getSpecialId2() {
return specialId2;
}
public void setSpecialId2(String specialId2) {
this.specialId2 = specialId2;
}
}
考虑两个同构 XML 模式。这里的同构是指这两个模式除了属性和标签名称之外具有相同的结构。更具体地说,我有一个活生生的例子,当是架构时,比如 A
,及其副本 B
,其中所有标签和属性名称都从英语翻译成等效的国家语言。
例如,作为输入,我们可以有一个对象的两个不同变体:
<tag_1_v1>
<tag_2_v1 id="blabla" name="xxxxx">
Some value1
</tag_2_v1>
<tag_3_v1 id="alalala" name="yyyyy">
Some value2
</tag_3_v1>
</tag_1_v1>
和
<tag_1_v2>
<tag_2_v2 special_id_2="blabla" name="xxxxx">
Some value1
</tag_2_v2>
<tag_3_v2 id="alalala" special_name_2="yyyyy">
Some value2
</tag_3_v2>
</tag_1_v2>
问题 是将这两个模式映射到单个 class 结构上,比方说
class Tag1 {
Tag2 tag2;
Tag3 tag3;
}
class Tag2 {
String id;
String name;
String value;
}
class Tag3 {
String id;
String name;
String value;
}
有多种解决此问题的想法,但所有想法都不是那么方便,因为在同一 class 结构上使用单个 JAXB 注释方案的可能性很大。他们是:
- 创建两个不同的 class 集,然后从对象中复制值 一个模式到另一个模式;
- 创建自己的 SAX 解析器实现并 "translate" 在其中将标签和属性名称转换为适当的名称;
- 使用 XML 自己的预处理器并使用字符串替换(如果 id 和属性名称在所有模式中不相同,则将不起作用)。
因为每个 <tag_i>
可以有不同的属性,一个干净的解决方案是使用继承:
- 创建一个由
Tag1V1
和Tag1V2
继承的摘要 classTag1
。将所有公共代码分解为Tag1
. Tag2
和Tag3
也是如此。
为了让你开始,下面是 Tag2
:
@XmlRootElement
@XmlSeeAlso({Tag2V1.class, Tag2V2.class})
abstract class Tag2 {
private String name;
private String content;
@XmlAttribute(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlValue
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
@XmlRootElement(name = "tag_2_v1")
class Tag2V1 extends Tag2 {
private String id;
@XmlAttribute(name = "id")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
@XmlRootElement(name = "tag_2_v2")
class Tag2V2 extends Tag2 {
private String specialId2;
@XmlAttribute(name = "special_id_2")
public String getSpecialId2() {
return specialId2;
}
public void setSpecialId2(String specialId2) {
this.specialId2 = specialId2;
}
}