I have some non-heirarchal xml that has pseudo-structure. Every object declares a parent (except the "root" object) and zero or more children, but does so using ids and reference attributes rather than a nested structure. I would like to convert this to a nested structure.
我有一些具有伪结构的非heirarchal 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>
For the record, the actual document also contains object definitions, which the objects also reference in an attribute, similar to a class but I need to retrieve the element name from the definition by, again, reference id. At some point in the process I convert the names of each "object" to "template" or "subsection". If it simplifies things I can perform this operation after applying the structure. I also have a tokenize "function" for the children attribute, as I am using XSLT 1.0, which doesn't have it built-in.
对于记录,实际文档还包含对象定义,对象也在属性中引用,类似于类,但我需要再次通过引用id从定义中检索元素名称。在这个过程中的某个时刻,我将每个“对象”的名称转换为“模板”或“子部分”。如果它简化了我可以在应用结构后执行此操作。我还为children属性设置了一个tokenize“function”,因为我使用的是XSLT 1.0,它没有内置的。
So for the example above I would like 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 object elements contain other information, attributes, data, etc. These have been removed to simplify the example, but may add a layer of complexity to the problem.
请记住,这些对象元素包含其他信息,属性,数据等。这些已被删除以简化示例,但可能会为问题添加一层复杂性。
If possible I would like to do this in an elegant and extensible way. I am not forced to but would prefer to use XSL 1.0 (so that it can be integrated with the existing server software).
如果可能的话,我想以优雅和可扩展的方式做到这一点。我不是*,而是更愿意使用XSL 1.0(以便它可以与现有的服务器软件集成)。
Thank you kindly to anyone who can help me or point me in the right direction!
非常感谢能帮助我或指导我正确方向的人!
2 个解决方案
#1
0
Without doing the full XSLT, you could structure your transform like below: Basically, the template for Books would call an apply-templates for chapters, and the template for chapters would apply-templates for topics, etc. The key here, is putting the id from the parent into a variable, so that you can use it in subsequent apply-template calls to find the children.
如果没有完整的XSLT,你可以像下面那样构建你的转换:基本上,Books的模板会调用章节的apply-templates,章节的模板会应用主题的模板等。这里的关键是放置id从父级转换为变量,以便您可以在后续的apply-template调用中使用它来查找子级。
<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>
#2
0
This short and simple, complete transformation:
这个简短而完整的转型:
<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 on the provided XML document:
当应用于提供的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>
produces the wanted, 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.
说明:正确使用密钥。
#1
0
Without doing the full XSLT, you could structure your transform like below: Basically, the template for Books would call an apply-templates for chapters, and the template for chapters would apply-templates for topics, etc. The key here, is putting the id from the parent into a variable, so that you can use it in subsequent apply-template calls to find the children.
如果没有完整的XSLT,你可以像下面那样构建你的转换:基本上,Books的模板会调用章节的apply-templates,章节的模板会应用主题的模板等。这里的关键是放置id从父级转换为变量,以便您可以在后续的apply-template调用中使用它来查找子级。
<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>
#2
0
This short and simple, complete transformation:
这个简短而完整的转型:
<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 on the provided XML document:
当应用于提供的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>
produces the wanted, 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.
说明:正确使用密钥。