如何从Resource或EObject获取XML DOM的Document或Element?
从EMF Resource/EObject获取XML DOM对象的方法
一、从Resource获取XML DOM Document/Element
因为你加载的是XML文件,EMF默认会用XMLResource处理这类资源,直接强转后就能拿到DOM对象:
// 将Resource强转为XMLResource XMLResource xmlResource = (XMLResource) resource; // 获取整个XML的Document对象 Document document = xmlResource.getDocument(); // 获取XML根节点Element Element rootElement = document.getDocumentElement();
不确定资源类型时可以先做判断,避免强转报错:
if (resource instanceof XMLResource) { XMLResource xmlResource = (XMLResource) resource; Document domDoc = xmlResource.getDocument(); // 后续DOM操作逻辑 }
二、从EObject关联到对应DOM Element
如果要从具体的EObject实例拿到它对应的XML Element,用XMLResource的映射表即可:
XMLResource xmlResource = (XMLResource) resource; // 获取EObject到DOM节点的映射表 Map<EObject, Node> eObjectToDomMap = xmlResource.getEObjectToDOMMap(); // 传入你的EObject实例,拿到对应的Element Element targetElement = (Element) eObjectToDomMap.get(yourEObject);
版本兼容方案分析
一、直接用if判断+DOM操作的可行性
这种方式可行,但不推荐,问题在于:
- 版本迭代后会堆出大量if分支,代码臃肿难维护
- 绕开EMF生成的模型API,失去类型安全、自动映射的优势,容易出现标签拼写错误、节点为空等低级问题
- 浪费了EMF本身提供的版本迁移能力
二、更优的替代方案
1. 利用EMF原生版本迁移(推荐)
EMF本身支持模型版本演化,通过自定义资源加载逻辑就能自动兼容新旧版本:
- 自定义
XMLHelper,根据XML中的版本属性(比如根节点的version),把旧标签映射到新模型属性 - 示例代码:
// 注册自定义XML资源工厂 Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("xml", new XMLResource.Factory() { @Override public Resource createResource(URI uri) { XMLResource resource = new XMLResourceImpl(uri); // 替换默认XMLHelper为自定义实现 resource.getDefaultSaveOptions().put(XMLResource.OPTION_XML_HELPER, new VersionCompatXMLHelper(resource)); return resource; } }); // 自定义XMLHelper处理版本映射 class VersionCompatXMLHelper extends XMLHelperImpl { private String modelVersion; public VersionCompatXMLHelper(XMLResource resource) { super(resource); // 提前解析XML中的版本信息 try { Document doc = resource.getDocument(); modelVersion = doc.getDocumentElement().getAttribute("version"); } catch (Exception e) { modelVersion = "v2"; // 默认新版本 } } @Override protected EStructuralFeature findFeature(EClass eClass, String tagName) { // 版本1的TAG_A映射到模型的b属性 if ("v1".equals(modelVersion) && "TAG_A".equals(tagName)) { return eClass.getEStructuralFeature("b"); } // 新版本的TAG_B直接对应b属性 else if ("TAG_B".equals(tagName)) { return eClass.getEStructuralFeature("b"); } return super.findFeature(eClass, tagName); } }
这样加载XML时会自动完成标签到模型的适配,业务代码不需要关心版本差异。
2. 封装版本适配工具类
如果不想修改EMF资源逻辑,可以把版本判断逻辑集中到工具类,依然用EMF模型API:
public class ModelVersionTool { public static Object getTargetValue(Object model, String version) { if ("v1".equals(version)) { return ((ModelClassV1) model).getA(); } else { return ((ModelClassV2) model).getB(); } } }
这种方式比直接操作DOM安全,且版本判断逻辑集中,便于后续修改。
3. 适配器模式解耦版本逻辑
定义统一接口,针对不同版本模型实现适配器,避免代码里堆if分支:
// 统一适配接口 public interface ModelAdapter { Object getTargetValue(); } // 版本1模型适配器 public class V1ModelAdapter implements ModelAdapter { private ModelClassV1 model; public V1ModelAdapter(ModelClassV1 model) { this.model = model; } @Override public Object getTargetValue() { return model.getA(); } } // 版本2模型适配器 public class V2ModelAdapter implements ModelAdapter { private ModelClassV2 model; public V2ModelAdapter(ModelClassV2 model) { this.model = model; } @Override public Object getTargetValue() { return model.getB(); } } // 使用时 ModelAdapter adapter; if ("v1".equals(version)) { adapter = new V1ModelAdapter((ModelClassV1) model); } else { adapter = new V2ModelAdapter((ModelClassV2) model); } Object targetValue = adapter.getTargetValue();
新增版本时只需要加新的适配器类,不需要修改原有业务代码,符合开闭原则。
内容的提问来源于stack exchange,提问作者R4de
相关产品推荐
相关产品推荐

