我有一些具有伪结构的非继承xml。每个对象都声明一个父对象("根"对象除外)和零个或多个子对象,但使用id和引用属性而不是嵌套结构。我想将其转换为嵌套结构。
<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>
对于记录,实际文档还包含对象定义,对象也在属性中引用这些对象定义,类似于类,但我需要通过引用id从定义中检索元素名称。在这个过程中的某个时刻,我将每个"对象"的名称转换为"模板"或"小节"。如果它简化了事情,我可以在应用该结构后执行此操作。我还为children属性提供了一个标记化的"函数",因为我使用的是XSLT1.0,它没有内置它。
所以对于上面的例子,我想要这个输出:
<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>
请记住,这些对象元素包含其他信息、属性、数据等。为了简化示例,这些元素已被删除,但可能会给问题增加一层复杂性。
如果可能的话,我想以一种优雅和可扩展的方式来做这件事。我不是被迫的,而是更喜欢使用XSL1.0(这样它就可以与现有的服务器软件集成)。
衷心感谢任何能帮助我或为我指明正确方向的人!
如果不执行完整的XSLT,您可以像下面这样构建转换:基本上,Books的模板将调用章节的应用模板,章节的模板将应用主题的模板,等等。这里的关键是将父级的id放入一个变量中,这样您就可以在随后的应用模板调用中使用它来查找子级。
<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>
这个简短而简单的完整转换:
<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>
应用于所提供的XML文档时:
<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>
生成所需的正确结果:
<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>
说明:正确使用钥匙。