views:

397

answers:

2

This is a bit of a vague notion which I have been running over in my head, and which I am very curious if there is an elegant method of solving. Perhaps it should be taken as a thought experiment.

Imagine you have an XML schema with a corresponding XSL transform, which renders the XML as SVG in the browser. The XSL generates SVG with appropriate Javascript handlers that, ultimately, implement editing-like functionality such that properties of the objects or their locations on the SVG canvas can be edited by the user. For instance, an element can be dragged from one location to another.

Now, this isn't particularly difficult - the drag/drop example is simply a matter of changing the (x,y) coordinates of the SVG object, or a resize operation would be a simple matter of changing its width or height.

But is there an elegant way to have Javascript work on the DOM of the source XML document instead of the rendered SVG? Why, you ask? Well, imagine you have very complex XSL transforms, where the modification of one property results in complex changes to the SVG. You want to maintain simplicity in your Javascript code, but also a simple way to persist the modified XML back to the server.

Some possibilities of how this may function:

  1. After modification of the source DOM, simply re-run the XSL transform and replace the original. Downside: brute force, potentially expensive operation.
  2. Create id/class naming conventions in the source and target XML/SVG so elements can be related back to each other, and do an XSL transform on only a subset of the new DOM. In other words, modify temporary DOM, apply XSL to it, remove changed elements from SVG, and insert the new one. Downside: May not be possible to apply XSL to temporary in-browser DOMs(?). Also, perhaps a bit convoluted or ugly to maintain.

I think that it may be possible to come up with a framework that handles the second scenario, but the challenge would be making it lightweight and not heavily tied to the actual XML schema. Any ideas or other possibilities? Or is there maybe an existing method of doing this which I'm not aware of?

UPDATE: To clarify, as I mentioned in a comment below, this aids in separating the draw code from the edit code. For a more concrete example of how this is useful, imagine an element which determines how it is drawn dependent on the value of a property of an adjacent element. It's better to condense that logic directly in the draw code instead of also duplicating it in the edit code.

A: 

Maybe use can AJAX: Instead of editing the document locally, send editing commands for the original XML to the server which transforms again and then sends the new SVG back.

The main problem here will be what happens when you update the SVG element on the current page. Will drag'n'drop still feel smooth? If not, then you might have to resort to some mix of the two methods: Drag the SVG node using JavaScript and when the user drops the node, send an update to the server for a new SVG.

You will want to avoid trying to synchronize updates in XML and the local SVG (which would mean to replicate part of the XSLT in JavaScript -> stay on one world, don't mix).

Aaron Digulla
Daniel
I understand that; I just doubt that the visual feedback will survive the rerun of the local transform. On top of that, I know no way to tell the browser to apply the transform again: When your JS runs, you don't have the original document anymore since it's already been transformed and the browser doesn't keep a copy.
Aaron Digulla
Well, you can just load the XML manually, keep a copy around, and use transformNode() or a javascript library to apply the xslt in Javascript... then manually add it to your dom. But as you say, it's the speed that's the issue.
Daniel
+2  A: 

We have done this in our in-browser XML editor Xopus. You can see an example here. We load the XML source document, an XML Schema and an XSLT that outputs HTML+SVG. Internally we rewrite your XSLT into XSLT' which will allow us to track the output HTML+SVG back to the original XML that was the context in the XSL to output that HTML or SVG node. This is the framework you're referring to.

To facilitate editing we position a cursor over your XSLT output and update the XML DOM when you type or insert elements. After each change we will rerun the XSLT. For performance reasons we will compare the XSLT output with the previous output and apply the changes using HTML DOM operations to the WYSIWYG view.

We diff the two XSLT outputs using another XSLT. We can do so because we have modified the original XSLT (resulting in XSLT') so that is will output unique and persistant IDs for each output node. So all new nodes will have new IDs and missing IDs are removed nodes.

XSLT' is the rewritten version of the original XSLT you provide. It is still XSLT, but we've added a few things to it so it outputs IDs for all output nodes (we do so with yet another XSLT). Other than that it is functionally equivalent to your original XSLT.

Laurens - Xopus
Interesting to hear that it's viable. How are you diff'ing the two XSLT outputs?
Daniel
Or, also, what do you mean by `XSLT'`? something you do internally, or an established standard I haven't been able to find?
Daniel
We diff the two XSLT outputs using another XSLT. We can do so because we have modified the original XSLT (resulting in XSLT') so that is will output unique and persistant IDs for each output node. So all new nodes will have new IDs and missing IDs are removed nodes.
Laurens - Xopus
XSLT' is the rewritten version of the original XSLT you provide. It is still XSLT, but we've added a few things to it so it outputs IDs for all output nodes (we do so with yet another XSLT). Other than that it is functionally equivalent to your original XSLT.
Laurens - Xopus
That's pretty clever.. I'd like to see the XSL, but that's another question. Hope you don't mind, but I added your comments to the answer. If you want to elaborate on the diff XSL more, it'd be very welcome :)
Daniel
I can't give you our code (you can license that), but I can explain how it works. We feed our diff XSL the old XSL output and the new XSL output. Since we have modified the XSL to add IDs (the hard part), we use those and xsl:key to find all added and removed elements and attributes. The diff XSL will output update instructions: <add id="xxx"/><rem id="xxx"/> and something similar for changed text nodes. The DOM updater will use that to change the HTML/SVG DOM accordingly. You may be able to achieve the same result without IDs, but it will not be as fast. I hope this helps.
Laurens - Xopus