A project using TeDMeT contains four relevant project item types:
XSD files, normally a local copy of an external file
XML sample data, part of a unit test, and used for seeding of mapping code
Path alias classes, initially generated by seeding from an XML sample file
Mapping code, referring to the path alias classes
User workflow needs to consider:
how each of the items is created in the project
how the items are viewed and modified within the project
how modifications in one item affect another item
what restrictions on the format and limitations on supported features we impose
The description of an input or output message can be either:
imported from an external source URL
created from scratch using the XSD editor
automatically generated from an XML sample file
After creation, the XSD file can likewise be modified by:
updating from the original external source
editing the XSD file with the XSD editor or a text editor
extending with the data from another XML sample file
The path alias system work at the DOM level, so dealing with "any" type content or derived types
in terms of paths is possible. However, they cannot all be derived from the XSD. The current idea is
to let the user add paths manually that go beyond the explicit and non-derived paths described by the XSD grammar,
but not generate those from the XSD in the code completion "new path" dialog. Providing the repetition information
for path defined directly by the user is the responsibility of that user.
The sample XML data for an input or output message can be:
imported from an external file
created from the XSD using a sample generation tool (***link?)
created manually using an XML editor or text editor
An alias class is a regular Java class used to store path aliases.
It can optionally contain a reference to an XSD file in the project,
and to an XML sample file for seeding and unit testing.
The alias class could initially be generated:
empty, optionally with an XSD reference (no sample XML file used)
from an XSD, with a subset of all paths (e.g. all non-recursive)
seeded from a sample XML file, with no XSD present
seeded from a sample XML file, with a link to the XSD
After creation, the class file could be modified:
directly by the user, using a text editor or Java IDE
re-seeded from a sample XML file
extended with (a subset of) all paths from the XSD file
extended with specific paths added by the TeDMeT edit widget
The alias class is the nexus in the TeDMeT workflow. It stores both generated Java code, references to the XSD and sample data,
computed metadata (repetition information in the paths), persisted state (available path aliases and their mapping to paths),
and Java code added by the user. In this way, the alias class participated in the workflow both as a persistent object to
store state (links, aliases, computed info) and as a Java class referenced during the code completion action in the Java editor
when editing the mappings. Because it is used to persist state, we need to impose some restrictions on the format and contents for the alias class, forming the "contract" between the TeDMeT workflow and the user. If the user breaks these rules, the
TeDMeT workflow may not work properly (analogous to the user writing invalid Java code in the mappings); however, user errors should be reported early and the TeDMeT code should fail gracefully with clear and specific error messages.
Sample I/O, no XSD, create mapping from scratch
Required: an input and an output XML sample data file.
In NB, create a new plain Java project.
Edit the new skeleton Java class.
Activate the mapper palette.
Drag the mapper into the Java class; a dialog pops up.
Provide the input and output sample file paths to the dialog.
The dialog generates a sample mapping code block (the "seeded" code) at the drop point in source.
It also generates a unit test in the project, and copies the sample data files there.
It also generates a "guessed" XSD file in the project (Not yet implemented.)
Edit the seeded code, replacing the "FIXME" calls with literal values, "du.get(sp.)" calls, or more complex calculations for the output fields.
If the input node to an assignment (i.e. a "du.set(tp., )" call) may be missing at runtime, you can add a "du.has(sp.)" test before the assignment.
If there are loops (because of repeated elements in the output sample data) then you'll normally want to remove the plain assignments with index > 0 generated after the loop, and change to loop to iterate over some repeated node in the input instead.
If you want to change the type of a field from String to something else, edit the generated XSD using the XSD editor or a text editor, then see use-case "Updating the XSD".
I/O XSDs, no sample data, create mapping from scratch
(...creating sample data from XSD...)
Using unseeded path in mapper
(...manual alias edit vs. tree panel...)
Updating the XSD
(...relaunch on alias class, changing path of XSD, reimport external XSD, separate what-if analysis?...)
Updating the sample
Re-seeding from new sample
Once the editor has created a seeded mapping, the user can modify this mapping, mainly by replacing the "FIXME" parts with references to source paths or literal values. Now three things may happen that would make the user want to apply seeding in the same mapping source again:
Adding a second mapping between the same two structures, perhaps to be called conditionally from somewhere else. In this case, the user can use the same mapping palette. This should be done in a separate method. The tooling needs to ensure the necessary imports for DomUtil etc. are only done once.
Updating the sample file, and wanting to replace the current mapping. We do not currently plan any kind of "merge" facility to combine generated seeding code with existing mapping code that may have been modified by the user. In this case, the user can either manually remove the existing mapping and then re-seed, or first create new seeded code next to the existing code and then manually merge the two.
Manually adding paths
(...sanctity of annotations?...)
(May need to move this to a separate page.)
After trying to come up with a clean definition of relative paths and their distinction to absolute paths, and designing interfaces to convert between the two, the best conclusion seems to be that such a clear-cut categorical distinction is not helpful. In a sense, all paths are relative: absolute paths are just relative to a point in a DOM tree that we choose to treat as a document root. When message substructures can be shared between message definitions (cf. comple types in XSD), including top-level structures (e.g. a message appearing either in isolation or as a payload of another message, or a temporary variable pointing to a subtree of a DOM tree), the distinction between "root" and "non-root" becomes meaningless other than as an aspect of a specific message definition use case.
The discussion on "relative paths" was triggered by a number of path use cases
observed in user projects:
storing a reference to a subtree in a temporary variable, and then using accessor chains from that variable, to either:
retain intermediate subtrees while modifying the original reference to it
cache the path, especially if it contains indices or is rather long
pass it as a parameter to a method operating on a shared subtree type
the use of subcollaborations
deep-copy facilites to operate on subtrees
A path is always defined with respect to a certain espected message (sub)structure. The relationship between a path an the structure that it refers to must be kept somewhere, if tooling is to let the user choose and create paths. In TeDMeT, the alias class is the nexus of this relationship, so it needs to store the reference to the message definition.
In the context of an alias class, we could define a "relative path" as being any path not defined relative to the root of the message structure, but relative to another path in the same alias class.
In TeDMeT tooling, relative path manipulation would crop up in a number of cases:
The Path class needs to provide primitives for "composing" a path from a first and second path (head and tail).
The Path class needs to provide support for non-leaf node paths, both for the head part of path composition, and for subcollab-like calls and deep-copy operations.
There must be a dialog to select/create new relative paths below a non-leaf path.
Some open questions:
Should relative paths be put into separate alias classes? Nested in another alias class or outside? What when shared? Parallels composite type def issues in XSD. Note that defining relative paths directly in an alias class does not allow them deriving their defined "root" implicitly from the alias class, so the information must be either an annotation on the individual relative path definition, or the relative paths must be grouped somehow, or the user needs to assert the path is valid.
Should we use a separate naming convention to make relative paths stand out?
Should we add subtree-level unmarshal/marshal facitities through DomUtil?
Both assignment (shallow reference copy) and structural copy (recursive, deep copy down to leaf nodes) are greatly desired by users. They are also full of potential pitfalls.
Not sure whether DOM interface can guarantee assignability, or clone-on-assign. DOM is just interface, underlying structure may reject objects not originated from tree.