@@ -72,32 +72,43 @@ public XPathContext newContext(XPathContext parentContext, T contextBean) {
7272 if (!(contextBean instanceof EObject rootObject )) {
7373 throw new IllegalArgumentException ();
7474 }
75- // TODO: consider parent-context (may be null). Require the context-bean to be
76- // from the same resource? Then we can also reuse all maps and the XPath object
77-
78- DocumentBuilder documentBuilder ;
79- try {
80- documentBuilder = DocumentBuilderFactory .newDefaultInstance ().newDocumentBuilder ();
81- } catch (ParserConfigurationException e ) {
82- throw new IllegalStateException (e );
75+ XPath xpath ;
76+ DOMMapping domMapping ;
77+ Element rootElement = null ;
78+
79+ if (parentContext != null ) {
80+ EObjectContext parent = (EObjectContext ) parentContext ;
81+ xpath = parent .xpath ;
82+ rootElement = parent .domMapping .getElement (contextBean );
83+ } else {
84+ xpath = XPATH_FACTORY .newXPath ();
8385 }
84- Document document = documentBuilder .newDocument ();
8586
86- XPath xpath = XPATH_FACTORY .newXPath ();
87- DefaultDOMHandlerImpl domMapping = new DefaultDOMHandlerImpl ();
88- Element rootElement = createElement (rootObject , document , domMapping );
89- xpath .setNamespaceContext (createNamespaceContext (rootElement ));
87+ if (rootElement != null ) {
88+ domMapping = ((EObjectContext ) parentContext ).domMapping ;
89+ } else {
90+ DocumentBuilder documentBuilder ;
91+ try {
92+ documentBuilder = DocumentBuilderFactory .newDefaultInstance ().newDocumentBuilder ();
93+ } catch (ParserConfigurationException e ) {
94+ throw new IllegalStateException (e );
95+ }
96+ Document document = documentBuilder .newDocument ();
9097
98+ domMapping = new DOMMapping ();
99+ rootElement = createElement (rootObject , document , domMapping );
100+ xpath .setNamespaceContext (createNamespaceContext (rootElement ));
101+ }
91102 return new EObjectContext (rootElement , domMapping , xpath );
92103 }
93104
94105 private static class EObjectContext implements XPathContext {
95106
96107 private final XPath xpath ;
97108 private final Element rootElement ;
98- private final DefaultDOMHandlerImpl domMapping ;
109+ private final DOMMapping domMapping ;
99110
100- private EObjectContext (Element rootElement , DefaultDOMHandlerImpl domMapping , XPath xpath ) {
111+ private EObjectContext (Element rootElement , DOMMapping domMapping , XPath xpath ) {
101112 this .rootElement = rootElement ;
102113 this .domMapping = domMapping ;
103114 this .xpath = xpath ;
@@ -192,7 +203,7 @@ private static Node getSingleNodeArgument(List<?> args) throws XPathFunctionExce
192203 }
193204 }
194205
195- private static Element createElement (EObject eObject , Document document , DefaultDOMHandlerImpl domMapper ) {
206+ private static Element createElement (EObject eObject , Document document , DOMMapping domMapper ) {
196207 new XMLSaveImpl (Map .of (), new XMIHelperImpl (), "UTF-8" ).save (null , document ,
197208 Map .of (XMLResource .OPTION_ROOT_OBJECTS , List .of (eObject )), domMapper );
198209 return document .getDocumentElement ();
@@ -226,6 +237,18 @@ public Iterator<String> getPrefixes(String namespaceURI) {
226237 };
227238 }
228239
240+ private static class DOMMapping extends DefaultDOMHandlerImpl {
241+
242+ public Element getElement (Object object ) {
243+ for (Map .Entry <Node , Object > entry : nodeToObject .entrySet ()) {
244+ if (Objects .equals (entry .getValue (), object )) {
245+ return (Element ) entry .getKey ();
246+ }
247+ }
248+ return null ;
249+ }
250+ }
251+
229252 private static Optional <Object > reconstructReferenceList (EObject first , String xpath , Iterator <Object > iterator ) {
230253 EReference containment = first .eContainmentFeature ();
231254 if (containment != null && containment .getUpperBound () == ETypedElement .UNBOUNDED_MULTIPLICITY
0 commit comments