使用 XML 创建结构图并通过 LaTeX 渲染
Creating a structural chart using XML and rendered via LaTeX
我正在尝试通过 XSLT 使用已经预定义的格式重新创建结构图表,即它们的外观单独定义。该结构是使用 XML 编写的,但后来在 xml2tex
、Xproc
库(https://github.com/transpect/xml2tex ).由于它们不是讨论的主要部分,所以我不进一步阐述它们。
我所拥有的是以下形式的示例结构:
<structure>
<structentry id="1" parent="0" caller="true">Root</structentry>
<structentry id="2" parent="1" caller="false">Child 1 of ID 1 (Root)</structentry>
<structentry id="3" parent="1" caller="false">Child 2 of ID 1 (Root)</structentry>
<structentry id="4" parent="1" caller="false">Child 3 of ID 1 (Root)</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>
理想情况下,输出应采用以下形式:
[{Root},fill=white[{Child 1 of ID 1 (Root)}][{Child 2 of ID 1 (Root)}][{Child 3 of ID 1 (Root)}[{Child 1 of ID 4}[{Child 1 of ID 5}]]]]
或者为了便于阅读:
[{Root},fill=white
[{Child 1 of ID 1 (Root)}]
[{Child 2 of ID 1 (Root)}]
[{Child 3 of ID 1 (Root)}
[{Child 1 of ID 4}
[{Child 1 of ID 5}]
]
]
]
然后看起来像这样:
因此,我试图通过匹配的 ID 将节点置于其父级之下。也就是说,任何具有 parent='1'
的节点都应该是具有 id='1'
.
的节点的子节点
我有以下转换,它使用 'dbk' (DocBook) 命名空间来定义输入 XML 中的节点。由于我是 XML、XSLT 和 XPath 的新手,所以在 xsl:template match="dbk:structentry"
之后我忍不住停留在这里。如果需要任何其他信息,我会很乐意更新它们。
<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>
更新
一个新问题是如何区分一个图表的根条目和另一个图表的根条目?这是 2 个结构的示例:
结构 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>
<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>
嗯,编写将产生您显示的结果的 XSLT 样式表并不难:
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>
我很难说这是否适合你的整体方案。
已添加:
如果您的 XML 文档有多个 structure
元素,但 id 在文档范围内是唯一的,您可以简单地更改指令:
<xsl:apply-templates select="key('child', 0)"/>
至:
<xsl:apply-templates select="key('child', 0, .)"/>
将键的范围限制在当前 structure
元素。这是假设您的处理器支持 XSLT 2.0 或更高版本。在 XSLT 1.0 中,您需要使用:
<xsl:apply-templates select="structentry[@parent=0]"/>
效率较低,因为 parent
值已被索引。
当然你还需要:
<xsl:template match="structure">
没有前导/
。
我正在尝试通过 XSLT 使用已经预定义的格式重新创建结构图表,即它们的外观单独定义。该结构是使用 XML 编写的,但后来在 xml2tex
、Xproc
库(https://github.com/transpect/xml2tex ).由于它们不是讨论的主要部分,所以我不进一步阐述它们。
我所拥有的是以下形式的示例结构:
<structure>
<structentry id="1" parent="0" caller="true">Root</structentry>
<structentry id="2" parent="1" caller="false">Child 1 of ID 1 (Root)</structentry>
<structentry id="3" parent="1" caller="false">Child 2 of ID 1 (Root)</structentry>
<structentry id="4" parent="1" caller="false">Child 3 of ID 1 (Root)</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>
理想情况下,输出应采用以下形式:
[{Root},fill=white[{Child 1 of ID 1 (Root)}][{Child 2 of ID 1 (Root)}][{Child 3 of ID 1 (Root)}[{Child 1 of ID 4}[{Child 1 of ID 5}]]]]
或者为了便于阅读:
[{Root},fill=white
[{Child 1 of ID 1 (Root)}]
[{Child 2 of ID 1 (Root)}]
[{Child 3 of ID 1 (Root)}
[{Child 1 of ID 4}
[{Child 1 of ID 5}]
]
]
]
然后看起来像这样:
因此,我试图通过匹配的 ID 将节点置于其父级之下。也就是说,任何具有 parent='1'
的节点都应该是具有 id='1'
.
我有以下转换,它使用 'dbk' (DocBook) 命名空间来定义输入 XML 中的节点。由于我是 XML、XSLT 和 XPath 的新手,所以在 xsl:template match="dbk:structentry"
之后我忍不住停留在这里。如果需要任何其他信息,我会很乐意更新它们。
<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>
更新
一个新问题是如何区分一个图表的根条目和另一个图表的根条目?这是 2 个结构的示例:
结构 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>
<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>
嗯,编写将产生您显示的结果的 XSLT 样式表并不难:
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>
我很难说这是否适合你的整体方案。
已添加:
如果您的 XML 文档有多个 structure
元素,但 id 在文档范围内是唯一的,您可以简单地更改指令:
<xsl:apply-templates select="key('child', 0)"/>
至:
<xsl:apply-templates select="key('child', 0, .)"/>
将键的范围限制在当前 structure
元素。这是假设您的处理器支持 XSLT 2.0 或更高版本。在 XSLT 1.0 中,您需要使用:
<xsl:apply-templates select="structentry[@parent=0]"/>
效率较低,因为 parent
值已被索引。
当然你还需要:
<xsl:template match="structure">
没有前导/
。