Получение узла xml в зависимости от дочернего значения с использованием xslt - PullRequest
0 голосов
/ 07 июня 2018

У меня есть один XML, как показано ниже

<BackgroundReports>
    <BackgroundReportPackage>
        <Screenings>
            <Screening type="PEMP">
                <ScreeningStatus>
                    <OrderStatus>Completed</OrderStatus>
                    <ResultStatus>Review</ResultStatus>
                </ScreeningStatus>
            </Screening>
            <Screening type="PEMP">
                <ScreeningStatus>
                    <OrderStatus>Completed</OrderStatus>
                    <ResultStatus>Review</ResultStatus>
                </ScreeningStatus>
            </Screening>
            <Screening type="FEMP">
                <ScreeningStatus>
                    <OrderStatus>Completed</OrderStatus>
                    <ResultStatus>Fail</ResultStatus>
                </ScreeningStatus>
            </Screening>
            <Screening type="PEMP">
                <ScreeningStatus>
                    <OrderStatus>Completed</OrderStatus>
                    <ResultStatus>Pass</ResultStatus>
                </ScreeningStatus>
            </Screening>
            <Screening type="TEST">
                <ScreeningStatus>
                    <OrderStatus>Completed</OrderStatus>
                    <ResultStatus>Review</ResultStatus>
                </ScreeningStatus>
            </Screening>
        </Screenings>
    </BackgroundReportPackage>
</BackgroundReports>

Я хочу получить только один Screening элемент типа атрибута PEMP и FEMP в зависимости от значения приоритета в значении <ResultStatus>.

Если XML имеет статус результата <ResultStatus>Fail</ResultStatus>, то получить только тот элемент Screening имеет <ResultStatus>Fail</ResultStatus>

Ouuput будет

<BackgroundReports>
    <BackgroundReportPackage>
        <Screenings>
            <Screening type="FEMP">
                <ScreeningStatus>
                    <OrderStatus>Completed</OrderStatus>
                    <ResultStatus>Fail</ResultStatus>
                </ScreeningStatus>
            </Screening>
            <Screening type="TEST">
                <ScreeningStatus>
                    <OrderStatus>Completed</OrderStatus>
                    <ResultStatus>Fail</ResultStatus>
                </ScreeningStatus>
            </Screening>
        </Screenings>
    </BackgroundReportPackage>
</BackgroundReports>

Удалено 3 элемента FEMP / PEMP Screeningиз исходного XML.

Второй приоритет - Review (если нет Fail) - <ResultStatus>Review</ResultStatus>, но также можно получить только один элемент, если несколько / все элементы Screening с Review

Thirdis Pass (если нет Review и Fail), но также получить только один элемент, если несколько / все элементы Screening с Pass

Также в нем должны быть перечислены другие Screening элементы, отличные от PEMP и FEMP

Вот xslt, с которым я работал до сих пор

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:ns0="http://www.cpscreen.com/schemas"
    xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xdt="http://www.w3.org/2005/02/xpath-datatypes"
    xmlns:my="http://www.fadv.com" exclude-result-prefixes="my fn xs xdt">
    <xsl:output method="xml" version="1.0" encoding="UTF-8"
        indent="yes" />

   <xsl:template match="node()|@*">
        <!-- Copy the current node -->
        <xsl:copy>
            <!-- Including any attributes it has and any child nodes -->
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/ns0:BackgroundReports/ns0:BackgroundReportPackage/ns0:Screenings">
        <test><xsl:value-of select="count(ns0:Screening)"/></test>
        <xsl:variable name="eduResultStatus"/>
        <xsl:for-each select="ns0:Screening[@type='PEMP' or @type='FEMP']">
            <!-- Yet to work here -->
        </xsl:for-each>

        <xsl:for-each select="ns0:Screening[@type != 'PEMP' and @type != 'FEMP']">
            <xsl:copy>
                <!-- Including any attributes it has and any child nodes -->
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

1 Ответ

0 голосов
/ 07 июня 2018

Поскольку вы используете XSLT 2.0, вы можете объявить порядок сортировки и разделить значения

<xsl:param name="sortOrder" select="'Fail,Review,Pass'" />
<xsl:variable name="valSequence" select="tokenize($sortOrder, ',')"/>

Выполнить сортировку на ResultStatus, используя заявленный порядок для элемента Screening, имеющего @typeзначения как FEMP и PEMP и получить 1-й элемент в выходных данных

<xsl:for-each select="Screening[@type = 'FEMP' or @type = 'PEMP']">
    <xsl:sort select="index-of($valSequence, ScreeningStatus/ResultStatus)" />
    <!-- Get 1st element after sorting -->
    <xsl:if test="position() = 1">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:if>
</xsl:for-each>

Для остальных узлов примените их как

<xsl:apply-templates select="Screening[not(@type = 'FEMP' or @type = 'PEMP')]" />

Полный XSLT такой, как показано ниже

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

    <xsl:param name="sortOrder" select="'Fail,Review,Pass'" />
    <xsl:variable name="valSequence" select="tokenize($sortOrder, ',')"/>

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

    <xsl:template match="Screenings">
        <xsl:copy>
            <xsl:for-each select="Screening[@type = 'FEMP' or @type = 'PEMP']">
                <xsl:sort select="index-of($valSequence, ScreeningStatus/ResultStatus)" />
                <!-- Get 1st element after sorting -->
                <xsl:if test="position() = 1">
                    <xsl:copy>
                        <xsl:apply-templates select="@* | node()" />
                    </xsl:copy>
                </xsl:if>
            </xsl:for-each>
            <xsl:apply-templates select="Screening[not(@type = 'FEMP' or @type = 'PEMP')]" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Выход

<BackgroundReports>
   <BackgroundReportPackage>
      <Screenings>
         <Screening type="FEMP">
            <ScreeningStatus>
               <OrderStatus>Completed</OrderStatus>
               <ResultStatus>Fail</ResultStatus>
            </ScreeningStatus>
         </Screening>
         <Screening type="TEST">
            <ScreeningStatus>
               <OrderStatus>Completed</OrderStatus>
               <ResultStatus>Review</ResultStatus>
            </ScreeningStatus>
         </Screening>
      </Screenings>
   </BackgroundReportPackage>
</BackgroundReports>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...