Is this possible: a "translator" that exports XD elements to a given structure in XML format or equivalent

Exporting to HTML is nowadays common. It turns graphical elements to HTML-code (I am no programmer, so programmers and developers can surely describe this way nicer).

My question is whether it is possible to create exporter / “translator” that turns graphical elements to something else than HTML, if provided with a “translation table”, ie element A turns into this text-string, which in turn is encapsuled in this string, ending up in a new file format that has a certain “code layout”.

Basically I am thinking if it is possible to turn XD into a front-end for designing script code for 3dsmax that builds UI elements.
I am rather new in XD as well, so I havent seen the range of plugins, nor how they work. For example, is it common to create predefined objects in a plugin that you drag-drop into XD workspace, so that they serve as “translator” objects, ie this item will turn into this code.
Or would it be sufficient to create a translation table, so that if I have a native XD element, say text, it will turn into this element once exported to the target language.

Forgive me for this possibly poor description, but I still hope I made my question clear. Looking forward to a discussion :smiley:

2 Likes

First of all: Welcome to the forums :wave: :slightly_smiling_face:.

If I understand you correctly, you’re asking whether it is possible to convert an XD document (i.e., all the information about its content) into another technical file format, e.g., XML or similar.

If that is the question, then yes, is absolutely possible to do so. All the information (except for very few exceptions which aren’t in the APIs, yet, like the Grid options) about the document are accessible for plugins and, since JS is a turing-complete language, you can basically produce any output you want :wink:.

About the “how” (as you wrote that you’re no programmer, I don’t know if this will help you, but to make this a useful answer instead of yes, it’s possible, I’ll write it anyway :stuck_out_tongue_winking_eye:):

Since the scenegraph is already structured in a tree format (the RootNode has several children which again have children if they are Groups and all of them have properties, meaning you can just iterate over them recursively and thereby build your XML/whatever tree.

The one area where it could get a little more complicated will be images, I don’t know what your reqirements in that area are?

After that, you can simply generate your string from whatever file structure you chose and ask the user for a location to save it (const file = await require('uxp').storage.localFileSystem.getFileForSaving(...);) and save the file there (await file.write(myString);).

I hope this helps,
Best,
Pablo

3 Likes

Thank you Pablo for a very educational answer. Also, thanks for not cutting me off, but instead explaining bits of the “how” - that was indeed the answer I was looking for instead of just a “yes” or even worse “go read the SDK and find out yourself” :wink:

Since you’re good in explaining things, I take the chance and ask some more.

Does it mean you would need to create a “translation” table of some sort (forgive me my lack of proper terminology) - and how could a translation table look like?
If I wanted to use something else than the predefined elements (lines, text and so on), can plugins create an own set of objects, for the sake of limitation and simplicity; you would only be able to export “XML” of those predefined elements. Would that be possible?

To shed more light over the matter, I created a little demo (XD-file provided here since the forum didn’t allow me, a new user, to attach files). And a screen capture follows below:
image

In destination code (3dsMax), this would translate to something like this - never mind the missmatching values compared to the XD-design. I simply copy pasted the original code from 3dsMax to show you what it really looks like:

rollout RelaxPolygonDemo “Relax Polygon” width:310 height:275
(
slider ‘slider_amount’ “Amount:” pos:[10,15] width:200 height:44 range:[0.05,1,0.5] align:#left
editText ‘amount_value’ pos:[60,15] width:50 height:15 align:#left
slider ‘slider_iteration’ “Iteration:” pos:[10,70] width:200 height:44 range:[1,100,10] align:#left
editText ‘iteration_value’ pos:[60,70] width:50 height:15 align:#left

label ‘lbl_axis’ “Smooth axis” pos:[10,120] width:40 height:15 align:#left
checkbox ‘chk_x’ “x” pos:[60,120] width:29 height:15 align:#left
checkbox ‘chk_t’ “y” pos:[100,120] width:29 height:15 align:#left
checkbox ‘chk_z’ “z” pos:[140,120] width:29 height:15 align:#left

checkbox ‘chk_outer’ “Keep outer” pos:[114,140] width:77 height:15 checked:true align:#left
checkbox ‘chk_border’ “Keep border” pos:[12,140] width:82 height:15 checked:true align:#left

button ‘btn_relax’ “Relax” pos:[51,168] width:80 height:21 align:#left
)

1 Like

First of all: Let’s look at how it would be possible to translate the “raw” elements. For that, you’d create a function that “translates” an arbitrary SceneNode into your language of choice and calls itself (recursively) for all of its child nodes:

const scenegraph = require('scenegraph');

function translate(node) {
  let translation = '';

  if (node instanceof scenegraph.Artboard)
    translation += 'Artboard (' + node.fillEnabled + ',' // append any properties you need
  else if (node instanceof scenegraph.Text)
    translation += [...]
  [...]

  if (node.children) {
    translation += ' children:{'
    for (let childNode of node.children.items) {
      translation += translate(childNode);
    }
    translation += '}';
  }
  translation+=');'
}

const myResult = translate(scenegraph.root);

(the translation this would generate wouldn’t be very useful, but it demonstrates how it could work in theory :wink:)


Regarding your goal:

I would argue that this is (at some level) achievable, but provides a few challenges that won’t be easy to overcome:

  • you have to detect – how should I put it – what is what in your XD document and detect it. For example, you’d have to detect a button by “it’s a group with a rectangle that’s filled with this tone of gray and also contains a text node with this font family and font size” (similar things, yet it only gets more complicated, with the sliders and checkboxes. Every text that doesn’t belong to something like this is considered to be a label, like “Smooth”
  • you have to somehow detect things like the sliders range. Again: it’s possible. You have its current value, the width of the slider and the current position of the handle, meaning it is feasible to calculate it, but let me just say it’s (excuse the language) darn hard :stuck_out_tongue_winking_eye:

All in all, I’d say creating something like this would be possible, but I doubt the resulting quality would be worth the effort. Except if you have far too much money to pay a not too small team of developers to do it, all you (or me) might be able to achieve would be a rudimentary “design to code” system the quality of which wouldn’t be worth the effort.

You might be able to adjust he project so that your plugin knows beforehand which element is which and you can only move and resize elements created by your plugin (which “remembers”, through sceneNode.pluginData, that that’s a [slider/checkbox/whatever], but that still would be a big effort (and one where I’m not sure it would be worth it).

It is, as stated, possible to do all of this (in one way or another), but the further you go away from a structure that’s unlike the one in XD, the more complex it becomes. For something like your case, you have to extract, in a sense, implementation logic like checked:true, range:[0.05,1,0.5] and so on. All in all, it is therefore possible to achieve this, but if you want to put that much effort into something like this where, probably 50% of the time, the outputted code won’t be what you’re looking for, is up to you to decide :slightly_smiling_face:

I hope this helps,
Best,
Pablo

1 Like

IIRC What you want to use is an XSLT on an XML document. My memory is a bit rusty on this.

You’d first want to export an XML document that has the scene graph, the artboard or the scene node into an XML representation. So something like this:

<SceneNode type="Artboard">
    <SceneNode x="10" y="10" type="Rectangle" fill="rgba(0,0,0,1)"/>
</SceneNode>

Then you have created a XSL or XSLT document that describes how to translate that document into another document (example XSLT found online):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/persons">
    <root>
      <xsl:apply-templates select="person"/>
    </root>
  </xsl:template>

  <xsl:template match="person">
    <name type="{@username}">
      <xsl:value-of select="name" />
    </name>
  </xsl:template>

</xsl:stylesheet>

You would then give both of those to a XML document processor and it would “translate” from one XML markup type to another. Web browsers like Firefox and Chrome have XSL processors built in.

The UXP architecture is sort of kind of an HTML browser but doesn’t support all the features browsers do. XML processing is not one of them (that I’m aware of).

How to transform XML to XML using XSLT.

Since XML transforms aren’t supported (yet?) in UXP I would do three things:

  • Make a feature request here on the forums
  • If you make a plugin yourself see below
  • See if it’s already done or could be added to an existing plugin

If you do it yourself you can create the XML in the plugin and then post or send that XML to a web server or web page you have setup that would use the browser to transform your XML using your XSLT stylesheet.

Sometimes companies already have markup in XML format and already have XSLT stylesheets so check with Autodesk.

But if you’re writing XML in the first place why not write it into the XML as you want it to be and skipping the XSLT? The code you posted doesn’t look like XML but more like JSON.

Some caveats: IIRC some developers have issues with XSLT in that it has some learning curve or some issues?

There are more examples online for “how to transform xml using xslt”.

@pklaschka, I totally understand the challenges to distinguish all the native XD elements and try to foresee what they were intended to mean in the end code. Starting from this end, this might even be more impossible than possible.

Therefore I asked beforehand if XD had the ability to allow “predefined” objects in plugins. I know, I should go and delve into the available plugins and see what there is. I am taking a shortcut and ask here instead :upside_down_face:
So, if we had a possibility to have predefined items, then we would have less things to worry about during the translation. An item could be a checkbox. The checkbox would export as a string saying “checkbox”. The item’s parameters could be “name”, “checked_status”, width and height and so on, and the item’s location could also be retrieved.
So all these parameters would simply be read by the translator and sent further so we end up like this

checkbox ‘the_name_defined_inXD’ “Defined_in_XD” pos:[114,140] width:77 height:15 checked:true

Now, the deciding question then; is it possible for plugins to have predefined objects/placeholders, aside to lines, rectangles, etc?

If no, then the option could be that the translator requires you to create an XD hiearchy that follows certain rules. And the translator would only look for those conditions, eg a rectangle named in a particular way (eg “button”) and once found, only then it would look into the width and height of that rectangle so that it would export it as target-code.
It would look further inside that particular tree, for a text-item of particular name, and take that name and use it as title for the button (because the translator knows by now that this is a button).

I dont know right now how this would be done altogether, but I am simply discussing and trying out ideas so that we might find ways that could realize an idea like this. :smiley:

If I understand that last correctly, the answer is “yes” – it’s just up to you to decide how you want to go about it.

For example, you could require that these components be grouped and then the group named in such a way that it reflects a checkbox of a specific type. Or, you could create these components, and then using a plugin set up some plugin metadata that would indicate that the component is a checkbox. Then, in the target document, the user duplicates that component, and you have another plugin that read the component’s metadata to detect its type.

For more info on the metadata API, see https://adobexdplatform.com/plugin-docs/reference/scenegraph.html#scenenodeplugindata--

1 Like

Thanks @kerrishotts for shedding more light onto the matter.
You don’t possibly know any examples that uses this method?

Also, I’d like to make sure I covered all questions before ending this post; what about the predefined objects, eg you drop something onto the artboard that is a “button” or a “checkbox”. Does XD support such thing?