I want to demonstrate XSL powerfullness for data exploration by solving the following problem: Given an xml file that describes some kind of "entity-relashionship" model, and for one entity in that model given by a name (assuming an attribute of the XML schema is used as identifier), I want a transformation that produce a new XML model that contains the given entity, plus all of its relatives as per the "Transitive closure of the dependencies relationship" of that given entity.
For example, the input XML model is
<root>
<!-- my model is made of 3 entities : leaf, composite and object -->
<!-- the xml elements are <leaves>, <composites> and <objects> are just placeholders for these entities -->
<!-- These placeholders are exepected to be in that order in the output as well as in the input (Schema constraints) -->
<leaves>
<!-- A, B, C are 3 types of different leaf nodes with their proper semantic in the model -->
<A name="f1" others="oooo"/>
<A name="f2" others="xxxx"/>
<B name="f3" others="ssss"/>
<C name="f4" others="gggg"/>
</leaves>
<composites>
<!-- composites containes only struct and union element -->
<struct name="structB" others="yyyy">
<!-- composite pattern, struct can embed struct in a tree-ish fashion -->
<sRef name="s6" nameRef="structA"/>
<!-- order of declaration does not matter !!! here in the XML, structA is not yet declared but file is valid -->
<uRef name="u7" nameRef="unionX"/>
</struct>
<!-- union is another kind of composition -->
<union name="unionX" others="rrrr">
<vRef name="u3" nameRef="f3" others="jjjj">
<vRef name="u4" nameRef="f2" others="pppp">
</union>
<struct name="structA" others="hhhh">
<vRef name="v1" nameRef="f1" others="jjjj">
<vRef name="v2" nameRef="f4" others="pppp">
</struct>
</composites>
<objects>
<object name="objB" others="tttt">
<field name="field1" nameRef="unionX" others="qqqq"/>
<field name="field2" nameRef="f2" others="cccc"/>
</object>
<object name="objC" others="nnnn">
<field name="fieldX" nameRef="structB" others="uuuu"/>
<field name="fieldY" nameRef="" others="mmmm"/>
</object>
<object name="objMain" others="nnnn">
<field name="fieldY" nameRef="structA" others="mmmm"/>
<field name="fieldY" nameRef="f3" others="mmmm"/>
<field name="object4" nameRef="objB" others="wwwww"/>
</object>
</objects>
<root>
I would like a transformation that,for a given name, creates a copy of the model with only information related to the element of this name, and of its dependencies described by the nameRef attributes.
so for the element "field1" the output would be
<root>
<leaves>
<A name="f1" others="oooo"/>
</leaves>
<!-- composites and objects placeholders shall be copied even when no elements in the graph traversal -->
<composites/>
<objects/>
<root>
whereas for "objB" the exepected output would be
<root>
<leaves>
<!-- element "f2" shall be copied only once in the output, althought the node is encountered twice in the traversal of "objB" tree :
- "f2" is referenced under "field2" of "obj2"
- "f2" is referenced under "u4" of "unionX" that is referencd under "field1" of "obj2"
-->
<A name="f2" others="xxxx"/>
<B name="f3" others="ssss"/>
</leaves>
<composites>
<union name="unionX" others="rrrr">
<vRef name="u3" nameRef="f3" others="jjjj">
<vRef name="u4" nameRef="f2" others="pppp">
</union>
<composites>
<objects>
<object name="objB" others="tttt">
<field name="field1" nameRef="unionX" others="qqqq"/>
<field name="field2" nameRef="f2" others="cccc"/>
</object>
</objects>
<root>
and so on an so forth.
From now on, I workout on a basic XSL but not very satisfying for the following reasons :
I have only some feelings and "intuitions" about the good and elegant way to do it.
For simplification you can make the following assumptions:
the "empty" xml output model should be as follows (due to schema constraints)
<root>
<leaves/>
<composites/>
<objects/>
<root>
To complete : the xslt processor I am currently using is Saxon XSLT proc with and the version of XSLT is 2.0 Thanks for helping ... I don't give you the xsl that I am not proud of, but if it appears helpfull, I will ...
I tried to implement "a transformation that,for a given name, creates a copy of the model with only information related to the element of this name, and of its dependencies described by the nameRef attributes" at https://xsltfiddle.liberty-development.net/gWEamLs/6:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="start-name" as="xs:string">objB</xsl:param>
<xsl:key name="name-ref" match="*[@name]" use="@name"/>
<xsl:function name="mf:traverse" as="element()*">
<xsl:param name="start" as="element()?"/>
<xsl:sequence select="$start, $start/*, $start/*[@nameRef]!key('name-ref', @nameRef, root(.))!mf:traverse(.)"/>
</xsl:function>
<xsl:param name="start-element" as="element()?" select="key('name-ref', $start-name)"/>
<xsl:variable name="named-elements" select="mf:traverse($start-element)"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="*[@name and not(. intersect $named-elements)]"/>
</xsl:stylesheet>
Based on a key and a recursive function the code "first" computes the related elements as a sequence of element nodes in a global variable and "then" the identity transformation set up declaratively by <xsl:mode on-no-match="shallow-copy"/>
just gets extended by an empty template for those elements having a name
attribute but not having been found by the recursive function as being related to the start element, ensuring any not related elements that way don't get copied to the output.