How to use XSLT 1.0 to add structure to a non-hierarchical XML file?

I have a non-hierarchical xml that has a pseudo structure. Each object declares a parent (except for the "root" object) and zero or more children, but does so using identifiers and reference attributes, rather than a nested structure. I would like to convert it to a nested structure.

<document> <object id="6" children="12,15"/> <object id="12" parent="6" children="13,18"/> <object id="13" parent="12" children="14,16,17"/> <object id="14" parent="13"/> <object id="15" parent="6" children="21,22"/> <object id="16" parent="13"/> <object id="17" parent="13"/> <object id="18" parent="12" children="23,25"/> <object id="19" parent="23"/> <object id="21" parent="15"/> <object id="22" parent="15"/> <object id="23" parent="18" children="19,24"/> <object id="24" parent="23"/> <object id="25" parent="18"/> </document> 

For the record, the actual document also contains object definitions, which objects also refer to an attribute similar to the class, but I need to get the element name from the definition, again, the link identifier. At some point in the process, I convert the names of each “object” to a “template” or “subsection”. If this simplifies, I can perform this operation after applying the structure. I also have a tokenize function for the children attribute, since I am using XSLT 1.0, which does not have a built-in module.

So, for the example above, I would like to get this output:

 <document> <object id="6"> <object id="12"> <object id="13"> <object id="14"/> <object id="16"/> <object id="17"/> </object> <object id="18"> <object id="23"> <object id="19"/> <object id="24"/> </object> <object id="25"/> </object> </object> <object id="15"> <object id="21"/> <object id="22"/> </object> </object> </document> 

Please keep in mind that these elements of the object contain other information, attributes, data, etc. They were removed to simplify the example, but may add a level of complexity to the problem.

If possible, I would like to do it in an elegant and extensible way. I am not forced, but would prefer to use XSL 1.0 (so that it can be integrated with existing server software).

Thank you for everyone who can help me or point me in the right direction!

+1
source share
2 answers

Without performing the full XSLT, you can structure your transformation as shown below: Basically, a template for books will call template templates for chapters, and a template for chapters will apply templates for themes, etc. The key point here is to transfer the identifier from the parent to the variable so that you can use it in subsequent calls to the query template to search for children.

 <document> <xsl:apply-templates select="/document/book" /> </document> <xsl:template match="/document/book"> <xsl:variable name="bookid"> <xsl:value-of select="@id"/> </xsl:variable> <xsl:element name="book"> <xsl:attribute name="id"> <xsl:value-of select="@id"/> </xsl:attribute> <xsl:apply-templates select="/document/chapter[@parent=$bookid]" /> </xsl:element> </xsl:template> <xsl:template match="/document/chapter"> Template for chapter would be replicated from the book template above . . . </xsl:template> 
0
source

This is a short and simple, complete conversion :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:key name="kChildren" match="object" use="@parent"/> <xsl:template match="/*"> <document> <xsl:apply-templates select="*[not(@parent)]"/> </document> </xsl:template> <xsl:template match="object"> <object id="{@id}"> <xsl:apply-templates select="key('kChildren', @id)"/> </object> </xsl:template> </xsl:stylesheet> 

when applied to the provided XML document :

 <document> <object id="6" children="12,15"/> <object id="12" parent="6" children="13,18"/> <object id="13" parent="12" children="14,16,17"/> <object id="14" parent="13"/> <object id="15" parent="6" children="21,22"/> <object id="16" parent="13"/> <object id="17" parent="13"/> <object id="18" parent="12" children="23,25"/> <object id="19" parent="23"/> <object id="21" parent="15"/> <object id="22" parent="15"/> <object id="23" parent="18" children="19,24"/> <object id="24" parent="23"/> <object id="25" parent="18"/> </document> 

creates the desired, correct result :

 <document> <object id="6"> <object id="12"> <object id="13"> <object id="14"/> <object id="16"/> <object id="17"/> </object> <object id="18"> <object id="23"> <object id="19"/> <object id="24"/> </object> <object id="25"/> </object> </object> <object id="15"> <object id="21"/> <object id="22"/> </object> </object> </document> 

Explanation . Proper use of keys.

0
source

Source: https://habr.com/ru/post/1415061/


All Articles