XSLT: получить предыдущее значение в каждом цикле - PullRequest
0 голосов
/ 25 мая 2020

У меня есть следующее XML:

<DELVRY07>
<IDOC BEGIN="1">
    <E1EDL20 SEGMENT="1">
        <E1EDL24 SEGMENT="1">
            <POSNR>000010</POSNR>
            <E1EDL37 SEGMENT="1">
                <EXIDV>123</EXIDV>
                <E1EDL38 SEGMENT="1">
                    <VHART_BEZ>SSCC Box</VHART_BEZ>
                    <MAGRV_BEZ>All materials</MAGRV_BEZ>
                    <VEBEZ>BOX - Parcel Express</VEBEZ>
                </E1EDL38>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000010</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000020</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000030</POSNR>
                </E1EDL44>
            </E1EDL37>
        </E1EDL24>
        <E1EDL24 SEGMENT="1">
            <POSNR>000020</POSNR>
            <E1EDL37 SEGMENT="1">
                <EXIDV>123</EXIDV>
                <E1EDL38 SEGMENT="1">
                    <VHART_BEZ>SSCC Box</VHART_BEZ>
                    <MAGRV_BEZ>All materials</MAGRV_BEZ>
                    <VEBEZ>BOX - Parcel Express</VEBEZ>
                </E1EDL38>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000010</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000020</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000030</POSNR>
                </E1EDL44>
            </E1EDL37>
        </E1EDL24>
        <E1EDL24 SEGMENT="1">
            <POSNR>000030</POSNR>
            <E1EDL37 SEGMENT="1">
                <EXIDV>456</EXIDV>
                <E1EDL38 SEGMENT="1">
                    <VHART_BEZ>SSCC Box</VHART_BEZ>
                    <MAGRV_BEZ>All materials</MAGRV_BEZ>
                    <VEBEZ>BOX - Parcel Express</VEBEZ>
                </E1EDL38>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000010</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000020</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000030</POSNR>
                </E1EDL44>
            </E1EDL37>
        </E1EDL24>
    </E1EDL20>
</IDOC>

Где я хочу удалить все сегменты E1EDL37, которые имеют то же значение EXIDV, что и предыдущий:

<DELVRY07>
<IDOC BEGIN="1">
    <E1EDL20 SEGMENT="1">
        <E1EDL24 SEGMENT="1">
            <POSNR>000010</POSNR>
            <E1EDL37 SEGMENT="1">
                <EXIDV>123</EXIDV>
                <E1EDL38 SEGMENT="1">
                    <VHART_BEZ>SSCC Box</VHART_BEZ>
                    <MAGRV_BEZ>All materials</MAGRV_BEZ>
                    <VEBEZ>BOX - Parcel Express</VEBEZ>
                </E1EDL38>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000010</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000020</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000030</POSNR>
                </E1EDL44>
            </E1EDL37>
        </E1EDL24>
        <E1EDL24 SEGMENT="1">
            <POSNR>000020</POSNR>
        </E1EDL24>
        <E1EDL24 SEGMENT="1">
            <POSNR>000030</POSNR>
            <E1EDL37 SEGMENT="1">
                <EXIDV>456</EXIDV>
                <E1EDL38 SEGMENT="1">
                    <VHART_BEZ>SSCC Box</VHART_BEZ>
                    <MAGRV_BEZ>All materials</MAGRV_BEZ>
                    <VEBEZ>BOX - Parcel Express</VEBEZ>
                </E1EDL38>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000010</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000020</POSNR>
                </E1EDL44>
                <E1EDL44 SEGMENT="1">
                    <VELIN>1</VELIN>
                    <VBELN>3030043338</VBELN>
                    <POSNR>000030</POSNR>
                </E1EDL44>
            </E1EDL37>
        </E1EDL24>
    </E1EDL20>
</IDOC>

Я пробовал это со следующим преобразованием XSLT, но это устранит все сегменты E1EDL37:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
    <DELVRY07>
        <IDOC BEGIN="1">
            <xsl:copy-of select="//EDI_DC40"/>
            <E1EDL20 SEGMENT="1">
                <VBELN><xsl:value-of select="/DELVRY07/IDOC/E1EDL20/VBELN"/></VBELN>
                <BTGEW><xsl:value-of select="/DELVRY07/IDOC/E1EDL20/BTGEW"/></BTGEW>
                <GEWEI><xsl:value-of select="/DELVRY07/IDOC/E1EDL20/GEWEI"/></GEWEI>
                <xsl:copy-of select="//E1ADRM1"/>
                <xsl:copy-of select="//E1EDT13"/>   
            <xsl:for-each select="/DELVRY07/IDOC/E1EDL20/E1EDL24">
                <E1EDL24 SEGMENT="1">
                    <xsl:variable name="position" select="."/>
                    <POSNR><xsl:value-of select="POSNR"/></POSNR>
                    <MATNR><xsl:value-of select="MATNR"/></MATNR>
                    <ARKTX><xsl:value-of select="ARKTX"/></ARKTX>
                    <LFIMG><xsl:value-of select="LFIMG"/></LFIMG>
                    <EAN11><xsl:value-of select="EAN11"/></EAN11>
                    <xsl:copy-of select="E1EDL41"/>

                    <xsl:variable name="pos" select="position()"/>                                                                      
                    <xsl:variable name="preceding-group-member" select="current-group()[$pos - 1]"/>
                    <xsl:variable name="this-data" select="E1EDL37/EXIDV"/>
                    <xsl:variable name="preceding-data" select="$preceding-group-member/E1EDL37/EXIDV"/>
                    <xsl:if test="$this-data != $preceding-data">
                        <xsl:copy-of select="E1EDL37"/>
                    </xsl:if>

                </E1EDL24>
            </xsl:for-each> 
            </E1EDL20>
        </IDOC>
    </DELVRY07>
</xsl:template>

Я не могу понять, почему это есть, и я уже несколько часов искал решение. Есть у кого-нибудь идеи, как это решить?

Ответы [ 3 ]

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

Используйте ключ для обнаружения дубликатов, аналогично методу Мюнхи :

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="k1" match="E1EDL37" use="EXIDV" />

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

<!-- remove duplicate E1EDL37s -->
<xsl:template match="E1EDL37[not(count(. | key('k1', EXIDV)[1]) = 1)]"/>

</xsl:stylesheet>
0 голосов
/ 25 мая 2020

Вы можете использовать xsl:for-each-group с group-adjacent, а затем выбрать первое в группе

<xsl:for-each-group select="E1EDL37" group-adjacent="EXIDV">
  <xsl:copy-of select="current-group()[1]"/>
</xsl:for-each-group>
0 голосов
/ 25 мая 2020

Вы можете упростить это с помощью шаблонов:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

        <xsl:template match="E1EDL37[EXIDV=preceding::E1EDL37[1]/EXIDV]"/>

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

</xsl:stylesheet>

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

...