@@ -71,32 +71,43 @@ public XPathContext newContext(XPathContext parentContext, T contextBean) {
7171 if (!(contextBean instanceof EObject rootObject )) {
7272 throw new IllegalArgumentException ();
7373 }
74- // TODO: consider parent-context (may be null). Require the context-bean to be
75- // from the same resource? Then we can also reuse all maps and the XPath object
76-
77- DocumentBuilder documentBuilder ;
78- try {
79- documentBuilder = DocumentBuilderFactory .newDefaultInstance ().newDocumentBuilder ();
80- } catch (ParserConfigurationException e ) {
81- throw new IllegalStateException (e );
74+ XPath xpath ;
75+ DOMMapping domMapping ;
76+ Element rootElement = null ;
77+
78+ if (parentContext != null ) {
79+ EObjectContext parent = (EObjectContext ) parentContext ;
80+ xpath = parent .xpath ;
81+ rootElement = parent .domMapping .getElement (contextBean );
82+ } else {
83+ xpath = XPATH_FACTORY .newXPath ();
8284 }
83- Document document = documentBuilder .newDocument ();
8485
85- XPath xpath = XPATH_FACTORY .newXPath ();
86- DefaultDOMHandlerImpl domMapping = new DefaultDOMHandlerImpl ();
87- Element rootElement = createElement (rootObject , document , domMapping );
88- xpath .setNamespaceContext (createNamespaceContext (rootElement ));
86+ if (rootElement != null ) {
87+ domMapping = ((EObjectContext ) parentContext ).domMapping ;
88+ } else {
89+ DocumentBuilder documentBuilder ;
90+ try {
91+ documentBuilder = DocumentBuilderFactory .newDefaultInstance ().newDocumentBuilder ();
92+ } catch (ParserConfigurationException e ) {
93+ throw new IllegalStateException (e );
94+ }
95+ Document document = documentBuilder .newDocument ();
8996
97+ domMapping = new DOMMapping ();
98+ rootElement = createElement (rootObject , document , domMapping );
99+ xpath .setNamespaceContext (createNamespaceContext (rootElement ));
100+ }
90101 return new EObjectContext (rootElement , domMapping , xpath );
91102 }
92103
93104 private static class EObjectContext implements XPathContext {
94105
95106 private final XPath xpath ;
96107 private final Element rootElement ;
97- private final DefaultDOMHandlerImpl domMapping ;
108+ private final DOMMapping domMapping ;
98109
99- private EObjectContext (Element rootElement , DefaultDOMHandlerImpl domMapping , XPath xpath ) {
110+ private EObjectContext (Element rootElement , DOMMapping domMapping , XPath xpath ) {
100111 this .rootElement = rootElement ;
101112 this .domMapping = domMapping ;
102113 this .xpath = xpath ;
@@ -191,7 +202,7 @@ private static Node getSingleNodeArgument(List<?> args) throws XPathFunctionExce
191202 }
192203 }
193204
194- private static Element createElement (EObject eObject , Document document , DefaultDOMHandlerImpl domMapper ) {
205+ private static Element createElement (EObject eObject , Document document , DOMMapping domMapper ) {
195206 new XMLSaveImpl (Map .of (), new XMIHelperImpl (), "UTF-8" ).save (null , document ,
196207 Map .of (XMLResource .OPTION_ROOT_OBJECTS , List .of (eObject )), domMapper );
197208 return document .getDocumentElement ();
@@ -225,6 +236,18 @@ public Iterator<String> getPrefixes(String namespaceURI) {
225236 };
226237 }
227238
239+ private static class DOMMapping extends DefaultDOMHandlerImpl {
240+
241+ public Element getElement (Object object ) {
242+ for (Map .Entry <Node , Object > entry : nodeToObject .entrySet ()) {
243+ if (Objects .equals (entry .getValue (), object )) {
244+ return (Element ) entry .getKey ();
245+ }
246+ }
247+ return null ;
248+ }
249+ }
250+
228251 private static Optional <Object > reconstructReferenceList (EObject first , String xpath , Iterator <Object > iterator ) {
229252 EReference containment = first .eContainmentFeature ();
230253 if (containment != null && containment .isMany () && xpath .endsWith ("/" + containment .getName ())) {
0 commit comments