1

我有一个带有组织层次结构的 XML 结构。该<pkEntity>元素是 org 的父 ID,并且<entityParent>是 org 的子元素。我不知道父/子组合的深度。我需要在下面提到的状态下进行转换:

 <EntityDimCollection>
<EntityDim>
<pkEntity>-9</pkEntity>
<entityParent>-7</entityParent>
<entityCode>Own_CP</entityCode>

<entityType>OT</entityType>
<essEntityCode>un.Own_CP</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>-8</pkEntity>
<entityParent>-7</entityParent>
<entityCode>Alternatives</entityCode>

<entityType>OT</entityType>
<essEntityCode>un.Alternatives</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>8555</pkEntity>
<entityParent>-8</entityParent>
<entityCode>Ex_BABRO</entityCode>

<entityType>CF</entityType>
<essEntityCode>un.Ex_BABRO</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>8752</pkEntity>
<entityParent>-8</entityParent>
<entityCode>Ex_SY</entityCode>

<entityType>CF</entityType>
<essEntityCode>un.Ex_SY</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>9731</pkEntity>
<entityParent>-8</entityParent>
<entityCode>NOR</entityCode>

<entityType>LE</entityType>
<essEntityCode>un.NOR</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>1649940</pkEntity>
<entityParent>9731</entityParent>
<entityCode>NO</entityCode>

<entityType>CG</entityType>
<essEntityCode>un.NOR.NO</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>1838293</pkEntity>
<entityParent>1649940</entityParent>
<entityCode>UKONORWAY</entityCode>

<entityType>CG</entityType>
<essEntityCode>un.NOR.UKONORWAY</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>1127251</pkEntity>
<entityParent>1838293</entityParent>
<entityCode>2BUS</entityCode>

<entityType>CG</entityType>
<essEntityCode>un.NOR.2BUS</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>1127274</pkEntity>
<entityParent>1127251</entityParent>
<entityCode>3BUS_B</entityCode>

<entityType>CG</entityType>
<essEntityCode>un.NOR.3BUS_B</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>1988187</pkEntity>
<entityParent>1127274</entityParent>
<entityCode>4BUS_B</entityCode>

<entityType>CG</entityType>
<essEntityCode>un.NOR.4BUS_B</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>1988188</pkEntity>
<entityParent>1988187</entityParent>
<entityCode>5ADM_B</entityCode>

<entityType>CG</entityType>
<essEntityCode>un.NOR.5ADM_B</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>1988189</pkEntity>
<entityParent>1988187</entityParent>
<entityCode>5FVK_B</entityCode>

<entityType>CG</entityType>
<essEntityCode>un.NOR.5FVK_B</essEntityCode>

</EntityDim>
<EntityDim>
<pkEntity>1988190</pkEntity>
<entityParent>1988189</entityParent>
<entityCode>61_FVK_B</entityCode>

<entityType>CG</entityType>
<essEntityCode>un.NOR.61_FVK_B</essEntityCode>

</EntityDim>
</EntityDimCollection>

并使用 Mark Veenstra 解决方案,我得到了这样的输出

<?xml version="1.0" encoding="UTF-8"?>
<client:LMSDetails xmlns:client="http://foo/bar">
   <client:ParentID>-9</client:ParentID>
   <client:ChildID>-7</client:ChildID>
   <client:name/>
   <client:identifier>OT</client:identifier>
   <client:isActive/>
   <client:ParentID>-8</client:ParentID>
   <client:ChildID>-7</client:ChildID>
   <client:name/>
   <client:identifier>OT</client:identifier>
   <client:isActive/>
   <client:children>
      <client:ParentID>8555</client:ParentID>
      <client:ChildID>-8</client:ChildID>
      <client:name/>
      <client:identifier>CF</client:identifier>
      <client:isActive/>
   </client:children>
   <client:children>
      <client:ParentID>8752</client:ParentID>
      <client:ChildID>-8</client:ChildID>
      <client:name/>
      <client:identifier>CF</client:identifier>
      <client:isActive/>
   </client:children>
   <client:children>
      <client:ParentID>9731</client:ParentID>
      <client:ChildID>-8</client:ChildID>
      <client:name/>
      <client:identifier>LE</client:identifier>
      <client:isActive/>
      <client:children>
         <client:ParentID>1649940</client:ParentID>
         <client:ChildID>9731</client:ChildID>
         <client:name/>
         <client:identifier>CG</client:identifier>
         <client:isActive/>
         <client:children>
            <client:ParentID>1838293</client:ParentID>
            <client:ChildID>1649940</client:ChildID>
            <client:name/>
            <client:identifier>CG</client:identifier>
            <client:isActive/>
            <client:children>
               <client:ParentID>1127251</client:ParentID>
               <client:ChildID>1838293</client:ChildID>
               <client:name/>
               <client:identifier>CG</client:identifier>
               <client:isActive/>
               <client:children>
                  <client:ParentID>1127274</client:ParentID>
                  <client:ChildID>1127251</client:ChildID>
                  <client:name/>
                  <client:identifier>CG</client:identifier>
                  <client:isActive/>
                  <client:children>
                     <client:ParentID>1988187</client:ParentID>
                     <client:ChildID>1127274</client:ChildID>
                     <client:name/>
                     <client:identifier>CG</client:identifier>
                     <client:isActive/>
                     <client:children>
                        <client:ParentID>1988188</client:ParentID>
                        <client:ChildID>1988187</client:ChildID>
                        <client:name/>
                        <client:identifier>CG</client:identifier>
                        <client:isActive/>
                     </client:children>
                     <client:children>
                        <client:ParentID>1988189</client:ParentID>
                        <client:ChildID>1988187</client:ChildID>
                        <client:name/>
                        <client:identifier>CG</client:identifier>
                        <client:isActive/>
                        <client:children>
                           <client:ParentID>1988190</client:ParentID>
                           <client:ChildID>1988189</client:ChildID>
                           <client:name/>
                           <client:identifier>CG</client:identifier>
                           <client:isActive/>
                        </client:children>
                     </client:children>
                  </client:children>
               </client:children>
            </client:children>
         </client:children>
      </client:children>
   </client:children>
   <client:ParentID>8555</client:ParentID>
   <client:ChildID>-8</client:ChildID>
   <client:name/>
   <client:identifier>CF</client:identifier>
   <client:isActive/>
   <client:ParentID>8752</client:ParentID>
   <client:ChildID>-8</client:ChildID>
   <client:name/>
   <client:identifier>CF</client:identifier>
   <client:isActive/>
   <client:ParentID>9731</client:ParentID>
   <client:ChildID>-8</client:ChildID>
   <client:name/>
   <client:identifier>LE</client:identifier>
   <client:isActive/>
   <client:children>
      <client:ParentID>1649940</client:ParentID>
      <client:ChildID>9731</client:ChildID>
      <client:name/>
      <client:identifier>CG</client:identifier>
      <client:isActive/>
      <client:children>
         <client:ParentID>1838293</client:ParentID>
         <client:ChildID>1649940</client:ChildID>
         <client:name/>
         <client:identifier>CG</client:identifier>
         <client:isActive/>
         <client:children>
            <client:ParentID>1127251</client:ParentID>
            <client:ChildID>1838293</client:ChildID>
            <client:name/>
            <client:identifier>CG</client:identifier>
            <client:isActive/>
            <client:children>
               <client:ParentID>1127274</client:ParentID>
               <client:ChildID>1127251</client:ChildID>
               <client:name/>
               <client:identifier>CG</client:identifier>
               <client:isActive/>
               <client:children>
                  <client:ParentID>1988187</client:ParentID>
                  <client:ChildID>1127274</client:ChildID>
                  <client:name/>
                  <client:identifier>CG</client:identifier>
                  <client:isActive/>
                  <client:children>
                     <client:ParentID>1988188</client:ParentID>
                     <client:ChildID>1988187</client:ChildID>
                     <client:name/>
                     <client:identifier>CG</client:identifier>
                     <client:isActive/>
                  </client:children>
                  <client:children>
                     <client:ParentID>1988189</client:ParentID>
                     <client:ChildID>1988187</client:ChildID>
                     <client:name/>
                     <client:identifier>CG</client:identifier>
                     <client:isActive/>
                     <client:children>
                        <client:ParentID>1988190</client:ParentID>
                        <client:ChildID>1988189</client:ChildID>
                        <client:name/>
                        <client:identifier>CG</client:identifier>
                        <client:isActive/>
                     </client:children>
                  </client:children>
               </client:children>
            </client:children>
         </client:children>
      </client:children>
   </client:children>
</client:LMSDetails>
4

1 回答 1

2

XSLT 1.0(和 XSLT 2.0)解决方案

它基于使用 <xsl:key> 来安排父母和孩子,同时提高解决方案的性能。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:client="http://client.org">

    <xsl:output method="xml" indent="yes" />

    <!-- Use keys to boost performance -->
    <xsl:key name="entity-key" match="EntityDim" use="pkEntity" />
    <xsl:key name="parent-key" match="EntityDim" use="entityParent" />

    <!-- Process root element -->
    <xsl:template match="EntityDimCollection">
        <client:LMSDetails>
            <!-- Apply template to root entities, i.e. entities with no parent nodes -->
            <xsl:apply-templates select="EntityDim[not(key('entity-key', entityParent))]" />
        </client:LMSDetails>
    </xsl:template>

    <!-- First one to use for the real parent -->
    <xsl:template match="EntityDim">
        <!-- Obtain the relevant information -->
        <client:ParentID><xsl:value-of select="pkEntity" /></client:ParentID>
        <client:ChildID><xsl:value-of select="entityParent" /></client:ChildID>
        <client:name/>
        <client:identifier><xsl:value-of select="entityType" /></client:identifier>
        <client:isActive/>
        <client:costCenter>
            <!-- Obtain the expression after the last dot in essEntityCode -->
            <xsl:call-template name="get-suffix">
                <xsl:with-param name="text" select="essEntityCode" />
            </xsl:call-template>
        </client:costCenter>
        <!-- Outputs the children for this node : we just search which entities have the
             current pkEntity as their entityParent-->
        <xsl:for-each select="key('parent-key', pkEntity)">
            <client:children>
                <xsl:apply-templates select="." />
            </client:children>
        </xsl:for-each>
    </xsl:template>

    <!-- Recursive template to obtain the suffix from essEntityCode (the part after
         the last dot ) -->
    <xsl:template name="get-suffix">
        <xsl:param name="text" />

        <!-- Check whether the current text contains a dot -->
        <xsl:choose>
            <!-- Case CONTAINS_DOT: recurse until there is not more dots in the string -->
            <xsl:when test="contains($text, '.')">
                <xsl:call-template name="get-suffix">
                    <xsl:with-param name="text" select="substring-after($text, '.')" />
                </xsl:call-template>            
            </xsl:when>
            <!-- Case WITHOUT_DOTS : output suffix -->
            <xsl:otherwise>
                <xsl:value-of select="$text" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

仅限 XSLT 2.0 的解决方案

构建层次结构的方式是一样的,唯一不同的是从essEntityCode获取后缀的方式。在 XSLT 1.0 中,我们必须构建一个递归模板来检测最后一个点并提取后缀。但是在 XSLT 2.0 中,我们可以使用 tokenize 函数,它使用给定的正则表达式拆分给定的字符串。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:client="http://client.org">

    <xsl:output method="xml" indent="yes" />

    <xsl:key name="entity-key" match="EntityDim" use="pkEntity" />
    <xsl:key name="parent-key" match="EntityDim" use="entityParent" />

    <xsl:template match="EntityDimCollection">
        <client:LMSDetails>
            <xsl:apply-templates select="EntityDim[not(key('entity-key', entityParent))]" />
        </client:LMSDetails>
    </xsl:template>

    <xsl:template match="EntityDim">
        <client:ParentID><xsl:value-of select="pkEntity" /></client:ParentID>
        <client:ChildID><xsl:value-of select="entityParent" /></client:ChildID>
        <client:name/>
        <client:identifier><xsl:value-of select="entityType" /></client:identifier>
        <client:isActive/>
        <client:costCenter>
            <!-- This is the only difference from the XSLT 1.0 solution, instead
                 of calling the recursive template we tokenize the expression and
                 obtain the last element (which is the suffix) -->
            <xsl:value-of select="tokenize(essEntityCode, '\.')[last()]" />
        </client:costCenter>
        <xsl:for-each select="key('parent-key', pkEntity)">
            <client:children>
                <xsl:apply-templates select="." />
            </client:children>
        </xsl:for-each>
    </xsl:template>

</xsl:stelesheet>

编辑:我假设为每个孩子创建一个新的 <client:children> ,可以通过调整 <for-each> 循环中的代码来更改该行为。

于 2013-02-19T16:44:31.620 回答