【问题标题】:XSLT: Select succeeding tags into child segments until next tagXSLT:将后续标签选择到子段中,直到下一个标签
【发布时间】:2020-05-28 00:17:44
【问题描述】:

我有以下输入 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 映射,如下所示,但我没有得到所需的输出。你能帮我解决这个问题吗?

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Record">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="*" group-starting-with="L_Record">
        <xsl:copy>
          <xsl:apply-templates select="@*,node(),current-group()[self::E_Record]"/>          
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

请帮我解决这个问题?
当我执行上述代码时,C_Record 和 R_Record 正在被删除。如何在输出中填充该数据?

【问题讨论】:

    标签: xslt xslt-2.0


    【解决方案1】:

    一种常见的方法是继续使用for-each-group group-starting-with,但随后在内部添加一个额外的检查是否匹配(例如L_Record):

      <xsl:template match="Record">
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:for-each-group select="*" group-starting-with="L_Record">
            <xsl:choose>
                <xsl:when test="self::L_Record">
                    <xsl:copy>
                      <xsl:apply-templates select="@*,node(),current-group()[self::E_Record]"/>          
                    </xsl:copy>
                    <xsl:apply-templates select="current-group()[not(self::L_Record | self::E_Record)]"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:template>
    

    https://xsltfiddle.liberty-development.net/bFWRApc/1 是您上一个问题中代码示例的扩展。

    【讨论】:

    • 代码使用 Saxon 处理器正常工作。但是我想要部署的系统没有 Saxon 处理器,也没有外部 SAXON 处理器。输入的 XML 是否可以使用 XSLT 1.0 版本进行转换?
    • @SrinivasBajina,也许,如果你发现有人想在 XSLT 1 中这样做。将问题标记为 XSLT 2 然后更改需求没有多大意义。
    • :: 我的错。代码很完美,我尝试调试并理解代码。但不幸的是,我正在部署的应用程序不支持 SAXON 处理器。我将查看是否有任何将 SAXON jar 文件安装到我的应用程序中的过程,并且还将找出是否可以使用 XSLT 1.0 完成的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 2021-09-14
    • 1970-01-01
    相关资源
    最近更新 更多