Re: [xsl] Got some cool XSLT code that assembles parts together to create larger parts?

Subject: Re: [xsl] Got some cool XSLT code that assembles parts together to create larger parts?
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Mon, 19 Mar 2012 16:28:55 -0400
At 2012-03-19 19:58 +0000, Costello, Roger L. wrote:
I need code that assembles parts together to create larger parts.

Here is a solution without checking for recursion.


t:\ftemp>type roger.xml
<?xml version="1.0" encoding="UTF-8"?>
<Document>
    <head id="head" idref="body" />

<body id="body" idref="leg" />

<leg id="leg" idref="toes" />

<toes id="toes" />

</Document>

t:\ftemp>xslt roger.xml roger.xsl
<?xml version="1.0" encoding="utf-8"?>
<Document>

   <head id="head">
      <body id="body">
         <leg id="leg">
            <toes id="toes"/>
         </leg>
      </body>
   </head>


<body id="body"> <leg id="leg"> <toes id="toes"/> </leg> </body>


<leg id="leg"> <toes id="toes"/> </leg>


<toes id="toes"/>



</Document> t:\ftemp>type roger.xsl <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">

<xsl:output indent="yes"/>

<xsl:key name="ids" match="*[@id]" use="@id"/>

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
    <xsl:apply-templates select="key('ids',@idref)"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="@idref"/>

</xsl:stylesheet>
t:\ftemp>

For example, consider this XML document:
...
It contains a lot of parts - head, body, leg, toes.

Each part references another part (except toes doesn't reference another part).

If a part references another part, I would like to inline the referenced part, and then recurses on the referenced part.

A perfect use of <xsl:apply-templates/>


After assembly the document should be this:
...

As above.


I wonder if this particular example is a special case of a general case of assembling parts together to create larger parts?

In any event, do you have some cool code that does the job?

Note that it's possible for a part A to reference a part B which references part A (i.e., circular reference). So the code must avoid going into an infinite loop.

That isn't evidenced in your data, so I've created an example and modified my solution. I'm using XSLT 1.0 ... this would be cleaner in XSLT 2.0 with strings.


t:\ftemp>type roger2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Document>
    <head id="head" idref="body" />

<body id="body" idref="leg" />

<leg id="leg" idref="toes" />

<toes id="toes" idref="body" />

</Document>

t:\ftemp>xslt roger2.xml roger2.xsl
<?xml version="1.0" encoding="utf-8"?>
<Document>

   <head id="head">
      <body id="body">
         <leg id="leg">
            <toes id="toes"/>
         </leg>
      </body>
   </head>


<body id="body"> <leg id="leg"> <toes id="toes"/> </leg> </body>


<leg id="leg"> <toes id="toes"> <body id="body"/> </toes> </leg>


<toes id="toes"> <body id="body"> <leg id="leg"/> </body> </toes>


</Document> t:\ftemp>type roger2.xsl <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">

<xsl:output indent="yes"/>

<xsl:key name="ids" match="*[@id]" use="@id"/>

<xsl:template match="@*|node()">
<xsl:param name="visited" select="concat(' ',@id,' ')"/>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:choose>
<xsl:when test="contains($visited,concat(' ',@idref,' '))">
<!-- avoid recursion -->
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="key('ids',@idref)">
<xsl:with-param name="visited" select="concat($visited,@idref,' ')"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>


<xsl:template match="@idref"/>

</xsl:stylesheet>
t:\ftemp>

I hope this helps, but I'm unsure if you have further requirements.

. . . . . . . . Ken

--
Contact us for world-wide XML consulting and instructor-led training
Free 5-hour video lecture: XSLT/XPath 1.0 & 2.0 http://ude.my/uoui9h
Crane Softwrights Ltd.            http://www.CraneSoftwrights.com/s/
G. Ken Holman                   mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
Google+ profile: https://plus.google.com/116832879756988317389/about
Legal business disclaimers:    http://www.CraneSoftwrights.com/legal

Current Thread