【问题标题】:Select sibling records until next tag using XSLT 1.0使用 XSLT 1.0 选择同级记录直到下一个标记
【发布时间】:2020-02-12 14:54:02
【问题描述】:

我有以下输入 XML。连续的 E_Records 是可选的,应该填充到 L_Record 中。我编写了以下 XSLT 编码。我应该做些什么改变吗?

输入 XML

<?xml version="1.0" encoding="UTF-8"?>
  <Record>
     <H_Record>
        <Rec_Type>H</Rec_Type>
     </H_Record>
     <C_Record>
        <Rec_Type>C</Rec_Type>
     </C_Record>
     <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
     </L_Record>
     <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>3</E_Qty>
     </E_Record>
     <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>4</E_Qty>
     </E_Record>
     <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
     </L_Record>
     <R_Record>
        <Rec_Type>R</Rec_Type>
     </R_Record>
  </Record>
  <Record>
     <H_Record>
        <Rec_Type>H</Rec_Type>
     </H_Record>
     <C_Record>
        <Rec_Type>C</Rec_Type>
     </C_Record>
     <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
     </L_Record>
     <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
     </L_Record>
     <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>1</E_Qty>
     </E_Record>
     <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>2</E_Qty>
     </E_Record>
     <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
     </L_Record>
     <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>5</E_Qty>
     </E_Record>
     <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>6</E_Qty>
     </E_Record>
     <R_Record>
        <Rec_Type>R</Rec_Type>
     </R_Record>
  </Record>

我期待的输出 XML 是

 <Record>
   <H_Record>
        <Rec_Type>H</Rec_Type>
   </H_Record>
   <C_Record>
        <Rec_Type>C</Rec_Type>
   </C_Record>
   <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
      <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>3</E_Qty>
      </E_Record>
      <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>4</E_Qty>
      </E_Record>
    </L_Record>
    <L_Record>
       <Rec_Type>L</Rec_Type>
       <L_Level>2</L_Level>
    </L_Record>
    <R_Record>
       <Rec_Type>R</Rec_Type>
    </R_Record>
  </Record>
  <Record>
     <H_Record>
        <Rec_Type>H</Rec_Type>
     </H_Record>
     <C_Record>
        <Rec_Type>C</Rec_Type>
     </C_Record>
     <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
     </L_Record>
     <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>      
       <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>1</E_Qty>
       </E_Record>
       <E_Record>
        <Rec_Type>E</Rec_Type>
        <E_Qty>2</E_Qty>
       </E_Record>
     </L_Record>
     <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>      
        <E_Record>
          <Rec_Type>E</Rec_Type>
          <E_Qty>5</E_Qty>
        </E_Record>
        <E_Record>
          <Rec_Type>E</Rec_Type>
          <E_Qty>6</E_Qty>
        </E_Record>
    </L_Record>
    <R_Record>
        <Rec_Type>R</Rec_Type>
     </R_Record>
  </Record>

我已经为此编写了 XSLT 映射,如下所示,但我没有得到所需的输出。你能帮我解决这个问题吗?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output omit-xml-declaration="yes" indent="yes"/>
         <xsl:template match="@* | node()">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
   </xsl:template>
   <xsl:template match="Record/L_Record">
   <L_Record>
    <xsl:variable name="header" select="."/>
            <xsl:apply-templates/>
            <xsl:if test = "not(following-sibling::L_Record)">
            <xsl:for-each select="following-sibling::E_Record[preceding-sibling::L_Record = $header]">
            <xsl:copy-of select="."/>
            </xsl:for-each>
            </xsl:if>
    </L_Record> 
    </xsl:template>
 </xsl:stylesheet>

请帮我解决这个问题?
当我执行上述代码时,记录 1 工作正常,但记录 2 工作不正常。 E-Record 段未出现在 L-Record 段中。

【问题讨论】:

    标签: xslt xslt-1.0


    【解决方案1】:

    您好,请测试此代码:

      <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="L_Record">
            <xsl:copy>
                <xsl:apply-templates/>
                <xsl:if test="following-sibling::*[1][self::E_Record]">
                <xsl:call-template name="Next_E_Record">
                    <xsl:with-param name="next" select="following-sibling::*[1][self::E_Record]"></xsl:with-param>
                </xsl:call-template>
                </xsl:if>
            </xsl:copy>
        </xsl:template>
    
       <xsl:template name="Next_E_Record">
           <xsl:param name="next"/>
           <xsl:copy-of select="$next"/>
           <xsl:if test="$next/following-sibling::*[1][self::E_Record]">
               <xsl:call-template name="Next_E_Record">
                   <xsl:with-param name="next" select="$next/following-sibling::*[1][self::E_Record]"></xsl:with-param>
               </xsl:call-template>
           </xsl:if>
       </xsl:template>
    
        <xsl:template match="E_Record"/>
    
    
    </xsl:stylesheet>
    

    请参阅转换 https://xsltfiddle.liberty-development.net/bFWRApe

    【讨论】:

    【解决方案2】:

    一种方法是遍历record 的子代,直到找到L_Record,然后添加兄弟姐妹,直到找到另一个L_Record

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="Record">
            <Record>
                <xsl:for-each select='*'>
                    <xsl:choose>
                        <xsl:when test='name()="E_Record"'/>
                        <xsl:when test='name()="L_Record"'>
                            <L_Record>
    
                                <xsl:copy-of select="*"/>
                                <xsl:call-template name='next'>
                                    <xsl:with-param name='current_L' select='.'/>
                                    <xsl:with-param name='remainder' select='following-sibling::*'/>
                                </xsl:call-template>
                            </L_Record>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:copy-of select="."/>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each>
            </Record>
        </xsl:template>
    
        <xsl:template name='next'>
            <xsl:param name='current_L'/>
            <xsl:param name='remainder'/>
            <xsl:param name='first' select='$remainder[1]'/>
    
            <xsl:if test='$remainder and not(name($first)="L_Record")'>
                <xsl:copy-of select="$first"/>
    
                <xsl:call-template name='next'>
                    <xsl:with-param name='current_L' select='$current_L'/>
                    <xsl:with-param name='remainder' select='$remainder[position() &gt; 1]'/>
                </xsl:call-template>
            </xsl:if>
        </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 我尝试了上面的代码,但是在第二个记录标签中,所有的 E_Record 都出现在第一个 L_Record 中,并且 E_Record 没有从记录中删除。
    【解决方案3】:

    您应该能够创建一个匹配E_Record 元素的xsl:key,并使用生成的第一个前面L_Record 兄弟的ID 作为键。

    然后就可以匹配L_Record元素,复制匹配key的节点集。

    示例...

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:key name="e_recs" match="E_Record" use="generate-id(preceding-sibling::L_Record[1])"/>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="L_Record">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
          <xsl:copy-of select="key('e_recs',generate-id())"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="E_Record"/>
    
    </xsl:stylesheet>
    

    小提琴:http://xsltfiddle.liberty-development.net/94Acsmd

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-09
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-28
      相关资源
      最近更新 更多