Добавить поля родственного узла в родительский узел с помощью XSLT - PullRequest
0 голосов
/ 27 мая 2020

Мое требование - переместить родственные поля E_record в L_Records. Не могли бы вы проверить, где мне не хватает logi c. Код XSLT помещает все поля E_record в каждый L_Record. Пожалуйста, проверьте вторую root 2nd L_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>
     </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>
  </root>

Я получаю

<root>
  <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>
         <Rec_Type>E</Rec_Type>
         <E_Qty>3</E_Qty>
         <Rec_Type>E</Rec_Type>
         <E_Qty>4</E_Qty>
      </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>
         <Rec_Type>E</Rec_Type>
         <E_Qty>1</E_Qty>
         <Rec_Type>E</Rec_Type>
         <E_Qty>2</E_Qty>
         <Rec_Type>E</Rec_Type>
         <E_Qty>5</E_Qty>
         <Rec_Type>E</Rec_Type>
         <E_Qty>6</E_Qty>
      </L_Record>
      <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
         <Rec_Type>E</Rec_Type>
         <E_Qty>5</E_Qty>
         <Rec_Type>E</Rec_Type>
         <E_Qty>6</E_Qty>
      </L_Record>
     <R_Record>
        <Rec_Type>R</Rec_Type>
     </R_Record>
  </Record>
  </root>

Ожидаемый результат:

<root>
  <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>
         <Rec_Type>E</Rec_Type>
         <E_Qty>3</E_Qty>
         <Rec_Type>E</Rec_Type>
         <E_Qty>4</E_Qty>
      </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>
         <Rec_Type>E</Rec_Type>
         <E_Qty>1</E_Qty>
         <Rec_Type>E</Rec_Type>
         <E_Qty>2</E_Qty>
         <Rec_Type>E</Rec_Type>
      </L_Record>
      <L_Record>
        <Rec_Type>L</Rec_Type>
        <L_Level>2</L_Level>
         <Rec_Type>E</Rec_Type>
         <E_Qty>5</E_Qty>
         <Rec_Type>E</Rec_Type>
         <E_Qty>6</E_Qty>
      </L_Record>
     <R_Record>
        <Rec_Type>R</Rec_Type>
     </R_Record>
  </Record>
  </root>

Вот выполненный код 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="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::*[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::*[self::E_Record]/*"></xsl:with-param>
           </xsl:call-template>
       </xsl:if>
   </xsl:template>

    <xsl:template match="E_Record"/>

</xsl:stylesheet>
enter code here

1 Ответ

1 голос
/ 27 мая 2020

Вы можете использовать это решение:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="1.0">

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

    <!-- Replace first E_Record in a Record -->
    <xsl:template match="E_Record[position()=1]">
        <L_Record>
            <Rec_Type>L</Rec_Type>
            <L_Level>2</L_Level>
            <!-- Copy all contents of E_Record siblings -->
            <xsl:copy-of select="../E_Record/*"/>
        </L_Record>
    </xsl:template>

    <!-- Eliminate all other E_Record -->
    <xsl:template match="E_Record"/>

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

</xsl:stylesheet>

Посмотрите, как это работает: https://xsltfiddle.liberty-development.net/6pS26n8

Обновленная версия:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="1.0">


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

    <!-- Replace E_Record immediately following an L_Record -->
    <xsl:template match="E_Record[name(preceding-sibling::*[1])='L_Record']">
        <L_Record>
            <Rec_Type>L</Rec_Type>
            <L_Level>2</L_Level>
            <!-- Copy the contents of the current E_Record -->
            <xsl:copy-of select="*"/>
            <!-- Call template to copy next E_Record -->
            <xsl:call-template name="copyNextE">
                <xsl:with-param name="next" select="following-sibling::*[1]"/>
            </xsl:call-template>
        </L_Record>
    </xsl:template>

    <!-- Recursive template, will call itself until the next sibling is not an E_Record -->
    <xsl:template name="copyNextE">
        <xsl:param name="next"/>
        <!-- If we are still dealing with an E_Record -->
        <xsl:if test="name($next)='E_Record'">
            <xsl:copy-of select="$next/*"/>
            <xsl:call-template name="copyNextE">
                <!-- Call the same template with the next sibling -->
                <xsl:with-param name="next" select="$next/following-sibling::*[1]"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <!-- Eliminate all other E_Record -->
    <xsl:template match="E_Record"/>

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

</xsl:stylesheet>

Смотрите здесь: https://xsltfiddle.liberty-development.net/6pS26n8/1

...