如何使用XSLT 1.0将结构添加到非heirarchal XML文件?

时间:2021-12-29 19:35:01

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.

说明:正确使用密钥。