2

Can an HTML form be bound to an XML document?

To give some context, Adobe XFA forms are XML documents created for purpose of rendering as a PDF form. They support XML bindings very similar to what I am looking for, but I'm not aware of anything similar in HTML forms and seeking suggestions.

An XFA form can also define bindings to an XML document that are bound to its form fields. It is not necessary for a schema to be defined - the form can be merged with XML data or it can generate XML data based on the bindings specified in the form.

Example form definition:

<subform layout="tb">
    <bind match="dataRef" ref="$.doc" />
    <field w="0.5in">
        <bind match="none" />
        <ui>
            <button />
        </ui>
        <caption>
            <value>Add</value>
        </caption>
        <event activity="click" name="event__click">
            <script contentType="application/x-javascript">
               this.resolveNode("itemList").instanceManager.addInstance();
            </script>
        <event>
    </field>
    <subform layout="tb" name="itemList">
        <bind match="dataRef" ref="$.item[*]">
        <occur min="1" max="-1" />
        <field w="2in">
            <bind match="dataRef" ref="$.name" />
            <ui>
                <textEdit />
            </ui>
            <caption>
                <value>Name</value>
            </caption>
        </field>
    </subform>
</subform>

If the form was rendered with no data, it would appear similar to:

enter image description here

If the form was merged with the following input data:

<doc>
   <item>
       <name>item1</name>
   </item>
   <item>
       <name>item2</name>
   </item>
   <item>
       <name>item3</name>
   </item>
</doc>

It would render similar to:

enter image description here

As you may notice in the form defintion code, Adobe XFA form is using its own XML language and expression syntax called SOM expressions. The first binding $.doc is binding to the top-level root node name doc.

The next binding $.item[*] is nested with the subform element and is relative to the $.doc binding.

The subform element is a container, similar to an HTML div element.

The subform is bound to item elements under the root doc element. the [*] syntax means that the subform will repeat itself for each item element in the xml document.

The occur element within the the subform element further qualifies how many instances can occur. The min=1 means that even if there are no item elements in the data merged into the form, it will automatically generate one. The max=-1 means there is no limit on the number of item instances.

The field element is bound to $.name. This means its value will update (or create) a name element under the current item.

The 'Add' button in the form creates new instances, Adobe Reader has a built-in Javascript engine and its own API to manage instances of the form that are persisted back to the XML data bound to the form.

Of course, the XML data can also be extracted from a saved PDF form.

There are many more capabilities in XFA forms such as conditional bindings, but I'm curious if something along these lines exists in HTML forms, perhaps some library that can link a form to an XML document and target them in a similar way.

XPATH would be ideal instead of the Adobe SOM expression syntax. Also, it would be ideal to have the XML posted from the form rather than name / value pairs that HTML forms would do by default.

yas
  • 3,520
  • 4
  • 25
  • 38
  • so you want to generate an HTML form from the XFA definition, or..? – mb21 Apr 20 '18 at 19:32
  • No, I found it difficult to explain what I'm looking for, and only example of something similar I could find is XFA. – yas Apr 21 '18 at 16:16
  • so you want to convert a submitted HTML form to XML? or fill out a form from an XML file? or both? on a website? if on a website, using what server-side stack? there might be server-side stuff that does that, or otherwise you can write it yourself in a couple of lines... but there's nothing built into HTML that does that for you. – mb21 Apr 21 '18 at 18:23
  • Are we talking about XSD (schema definitions), or XSLT (stylesheets) here? The former's about verifying your XML is well-formed, and the latter's about transforming your XML into something else (e.g. PDF XML). Being specific about which we want will help me a lot in this answer. – Josh from Qaribou Apr 24 '18 at 19:57
  • HTML is similar enough to XML that creating an XML form then converting to HTML is not really any easier than writing the HTML form directly. If you want to use an XML form for multiple formats, than there are the tools listed in the answers. – JustinCB Apr 27 '18 at 12:39
  • I guess I failed to explain the problem adequately. Its about *binding* XML nodes to HTML fields, not generating HTML from XML (which is pretty trivial). – yas Apr 27 '18 at 16:31

3 Answers3

0

I'm guessing that what you're looking for is XSLT. This lets you transform a well-formed document of one kind into another. If this is what you want, there's a good answer here already.

Josh from Qaribou
  • 6,776
  • 2
  • 23
  • 21
0

There are many ways to convert XML into an HTML form. This question sounds an awful lot like a tool recommendation, so the only thing to do is list options:

Method 1: This site walks the user through pasting an XML document, and then turns it into a form. It's pretty outdated, since the last change log was in 2006.

http://www.datamech.com/XMLForm/ enter image description here

Method 2: You can write the script yourself, by converting XML > JSON then JSON > HTMLForm.

  1. Converting the XML into JSON tools:
  2. Converting JSON into form tools:
M -
  • 26,908
  • 11
  • 49
  • 81
  • This is closer to what I'm looking for. I think, I do have to write the code myself though. I'm accepting this answer, as its the only one that is at least in the spirit of what I was asking about. – yas Apr 27 '18 at 16:36
0

In case other people stumble across this same question, you can get to exactly what you are looking for (creating html from xml documents) using xslt.

Think of this lonely post as your jumping off point to xslt. If you've never dealt with it before, it can be a little hard to digest. Fear not. Every journey begins with the first step. (etc. etc.)

Start with xml, and some idea of the html you want to create

So - for your example XML:

<doc>
    <item name="Item1" />
    <item name="Item2" />
    <item name="Item3" />
</doc>

Let's assume you want to create a fairly simple HTML snippit:

<form class="tb">
    <div><a class="btn btn-primary">Add</a></div>
    <ul>
        <li><label>Name</label><input type="text" class="form-control" value="Item1" /></li>
        <li><label>Name</label><input type="text" class="form-control" value="Item2" /></li>
        <li><label>Name</label><input type="text" class="form-control" value="Item3" /></li>
    </ul>
</form>

Next, build your Xslt

There's some work at the beginning, and some syntax to learn. But, if we cut to the chase, this is the xslt that you'll end up with. It's just text. Just another file that you can hard code, embed, store in a file, grab from a url, etc.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="html" />
<xsl:template match="doc">
<form class="tb">
    <div><a class="btn btn-primary">Add</a></div>
    <ul>
        <xsl:for-each select="item">
           <li><label>Name</label><input type="text" class="form-control" value="<xsl:value-of select="@name"/>" /></li>
        </xsl:for-each>
        <xsl:if test="count(item)=0">
           <li><label>Name</label><input type="text" class="form-control" value="" /></li>
        </xsl:if>
    </ul>
</form>
</xsl:template>

A few Xslt Notes

As you can see from the above, you setup a BASE document node to loop through with the <xsl:template match="doc"> tag. If your xml document has a doc node, then the html within the template is included. If there isn't a doc node, then it's skipped.

You can break out your xslt into different templates - and include them in the main template as well. It's pretty cool.

In the example above, we loop through your item nodes with an <xsl:for-each> tag, and we even have an "alternate" html which gets displayed if there are ZERO item tags (that's the empty input tag surrounded by <xsl:if test="count(item)=0">).

There are some really great xslt references out there, but I like the one from Microsoft because I can use the c# code below to get html from a specific xslt tempate and my xml doc.

Finally, put it all together

Once you have your xml (above) and your xslt (also above), you can use them both to generate a string of html that is as long and complicated as you'd like. This is an almost verbatim copy of the method we use to generate massive mortgage contracts from xslt and really complex xml documents. I swear - it's lightning quick, and produces thousands of pages of html every day for us.

private string GetHtmlFromXslt(string xml, string xslt) {
    XslCompiledTransform transform = new XslCompiledTransform();
    using (XmlReader reader = XmlReader.Create(new StringReader(xslt))) {
        transform.Load(reader);
    }
    StringWriter results = new StringWriter();
    using (XmlReader reader = XmlReader.Create(new StringReader(xml))) {
        transform.Transform(reader, null, results);
    }
    return results.ToString();
}

This is a .net core project file, referencing just System.Xml and System.Xml.Xsl - both of which are standard in System.Xml.

C-sharp!? Blech! Ach! The OP said JAVASCRIPT. Jeez...

I know you are a javascript guy. There are tools to do exactly the same thing (exactly) here and here.

I just haven't used those libraries because all of our xml is (a) private and (b) located on servers. But - I took a look at the code and they both follow the same approach -- one xml file and one xslt file, married with about 8-10 lines of actual code and producing a lovely html baby.

So. That's it. No tools. No third party plugins. No crazy json stuff.

Good luck! Can't wait to see what you crazy-kids create!

bri
  • 2,932
  • 16
  • 17