I am trying to recreate a structural chart through XSLT with already predefined formatting i.e, their appearance defined separately. The structure is written using XML but later transformed into LaTeX code using forest
package in directory tree style with the help of xml2tex
, an Xproc
library (
Hence, I am trying to put nodes under their parents through their matching ids. That is, any node having parent='1'
should be child of node having id='1'
.
I have the following transformation which uses 'dbk' (DocBook) namespaces for defining nodes in the input XML. Since I am very new in XML, XSLT and XPath, I can't help but remain stuck here after xsl:template match="dbk:structentry"
. If any additional information is required I will gladly update them.
<template context="dbk:structure">
<text>\begin{center}
</text>
<xsl:apply-templates select="dbk:caption"/>
<text>\rule[5pt]{0.8\textwidth}{0.4pt}
</text>
<text>
\begin{forest}</text>
<xsl:apply-templates select="dbk:structentry"/>
<text>\end{forest}</text>
<text>
\end{center}</text>
</template>
<xsl:template match="dbk:caption">
\textbf{<xsl:value-of select="."/>}

</xsl:template>
<xsl:template match="dbk:structentry">
<xsl:choose>
<xsl:when test="@parent eq '0' and @caller eq 'true'">
[{<xsl:value-of select="."/>},fill=white<xsl:apply-templates select="@parent eq '1'">]
</xsl:when>
<xsl:otherwise>
[{<xsl:value-of select="."/>}]
</xsl:otherwise>
</xsl:choose>
</xsl:template>
UPDATE
A new problem is how can I differentiate one root entry of a chart from the root entry of another chart? Here's an example of 2 structures:
Structure 1:
<structure>
<structentry id="1" parent="0" caller="true">Root 1</structentry>
<structentry id="2" parent="1" caller="false">Child 1 of ID 1 (Root 1)</structentry>
<structentry id="3" parent="1" caller="false">Child 2 of ID 1 (Root 1)</structentry>
<structentry id="4" parent="1" caller="false">Child 3 of ID 1 (Root 1)</structentry>
<structentry id="5" parent="4" caller="false">Child 1 of ID 4</structentry>
<structentry id="6" parent="5" caller="false">Child 1 of ID 5</structentry>
</structure>
Structure 2:
<structure>
<structentry id="7" parent="0" caller="true">Root 2</structentry>
<structentry id="8" parent="7" caller="false">Child 1 of ID 7 (Root 2)</structentry>
<structentry id="9" parent="7" caller="false">Child 2 of ID 7 (Root 2)</structentry>
<structentry id="10" parent="7" caller="false">Child 3 of ID 7 (Root 2)</structentry>
<structentry id="11" parent="10" caller="false">Child 1 of ID 10</structentry>
<structentry id="12" parent="11" caller="false">Child 1 of ID 11</structentry>
</structure>
CodePudding user response:
Well, it's not very difficult to write an XSLT stylesheet that will produce the result you show:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:key name="child" match="structentry" use="@parent" />
<xsl:template match="/structure">
<xsl:apply-templates select="key('child', 0)"/>
</xsl:template>
<xsl:template match="structentry">
<xsl:text>[{</xsl:text>
<xsl:value-of select="."/>
<xsl:text>}</xsl:text>
<xsl:if test="@parent=0">,fill=white</xsl:if>
<xsl:apply-templates select="key('child', @id)"/>
<xsl:text>]</xsl:text>
</xsl:template>
</xsl:stylesheet>
Whether that fits in your overall scheme is hard for me to tell.
Added:
If your XML document has multiple structure
elements, but the ids are unique document-wide, you can simply change the instruction:
<xsl:apply-templates select="key('child', 0)"/>
to:
<xsl:apply-templates select="key('child', 0, .)"/>
to limit the scope of the key to the current structure
element. This is assuming your processor supports XSLT 2.0 or higher. In XSLT 1.0 you would need to use:
<xsl:apply-templates select="structentry[@parent=0]"/>
which is less efficient, since the parent
values have already been indexed.
And of course you need to have:
<xsl:template match="structure">
without the leading /
.