Как сортировать / выбирать отличительные в XSLT при создании XML заголовка / подробностей - PullRequest
0 голосов
/ 08 октября 2019

У меня есть файл с записью заголовка и один ко многим подробным записям. Мне нужно создать ту же запись заголовка вместе с последней подробной записью для данного номера политики. Как написать XSLT для сортировки и выбора первой записи?

Я попытался поместить жестко закодированное значение между операторами «для каждого» в XSLT, чтобы увидеть, где происходит разрыв кода. Все, что находится после второго «для каждого», не отображается. Я искал там все выше и ниже, чтобы узнать, сможет ли кто-нибудь обработать заголовок с несколькими деталями, но я не смог найти ответ на этот вопрос.

Это то, что я получаю (упрощенно - естьнамного больше полей):

<ns0:Root xmlns:ns0="http://CORE.BizTalk.Applications.Schemas.PolicyFF">
    <Header>
        <RecordType>RecordType</RecordType>
        <RecordID>RecordID</RecordID>
        <PolicyNumber>PolicyNumber</PolicyNumber>
    </Header>
    <Detail>
        <RecordType>POL</RecordType>
        <RecordID>1</RecordID>
        <PolicyNumber>ABC 0000018 00</PolicyNumber>
    </Detail>
    <Detail>
        <RecordType>POL</RecordType>
        <RecordID>2</RecordID>
        <PolicyNumber>DEF0000019</PolicyNumber>
    </Detail>
    <Detail>
        <RecordType>POL</RecordType>
        <RecordID>3</RecordID>
        <PolicyNumber>DEF0000019</PolicyNumber>
    </Detail>
    <Detail>
        <RecordType>POL</RecordType>
        <RecordID>3</RecordID>
        <PolicyNumber>ABC 0000018 00</PolicyNumber>
    </Detail>
</ns0:Root>

Вывод имеет идентичный макет, но я только хочу увидеть это, так как RecordID является последним RecordID для обеих политик (отсортировано по убыванию RecordID для каждой политики):

<ns0:Root xmlns:ns0="http://CORE.BizTalk.Applications.Schemas.PolicyFF">
    <Header>
        <RecordType>RecordType</RecordType>
        <RecordID>RecordID</RecordID>
        <PolicyNumber>PolicyNumber</PolicyNumber>
    </Header>
    <Detail>
        <RecordType>POL</RecordType>
        <RecordID>3</RecordID>
        <PolicyNumber>DEF0000019</PolicyNumber>
    </Detail>
    <Detail>
        <RecordType>POL</RecordType>
        <RecordID>3</RecordID>
        <PolicyNumber>ABC 0000018 00</PolicyNumber>
    </Detail>
</ns0:Root>

Это XSLT, который я использую:

<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var" version="1.0" xmlns:ns0="http://CORE.BizTalk.Applications.Schemas.PolicyFF">
    <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
    <xsl:key name="policy" match="Root/Detail" use="PolicyNumber" />
    <xsl:template match="/">
        <xsl:apply-templates select="/ns0:Root" />
    </xsl:template>
    <xsl:template match="/ns0:Root">
        <ns0:Root>
            <Header>
                <RecordType>
                    <xsl:value-of select="Header/RecordType/text()" />
                </RecordType>
                <RecordID>
                    <xsl:value-of select="Header/RecordID/text()" />
                </RecordID>
                <PolicyNumber>
                    <xsl:value-of select="Header/PolicyNumber/text()" />
                </PolicyNumber>
            </Header>
            <xsl:for-each select="Detail">
                <xsl:for-each select="Detail[generate-id() = generate-id(key('policy', PolicyNumber)[1])]">
                    <xsl:for-each select="key('policy', PolicyNumber)">
                        <xsl:sort order="descending" select="RecordID" data-type="text"/>
                        <xsl:if test="position() = 1">
                            <Detail>
                                <xsl:copy-of select="./*" />
                            </Detail>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:for-each>
            </xsl:for-each>
        </ns0:Root>
    </xsl:template>
</xsl:stylesheet>

В настоящее время я получаю только запись заголовка с XSLT выше.

@ Martin-Honnen:Мне нужно отсортировать по RecordID по убыванию. Я взял ваш первый и второй XSLT и превратил их в один, но я все еще получаю только запись заголовка. Предложения?

<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var" version="1.0" xmlns:ns0="http://CORE.BizTalk.Applications.PPPL.TrisuraReports.Schemas.PolicyFF">
    <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
    <xsl:key name="policy" match="Root/Detail" use="PolicyNumber" />
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Detail[not(generate-id() = generate-id(key('policy', PolicyNumber)[1]))]"/>

    <xsl:template match="Detail[generate-id() = generate-id(key('policy', PolicyNumber)[1])]">
        <xsl:for-each select="key('policy', PolicyNumber)">
            <xsl:sort select="RecordID" data-type="text" order="descending"/>
            <xsl:if test="position() = 1">
                <xsl:copy-of select="."/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Ответы [ 2 ]

1 голос
/ 08 октября 2019

В XSLT 1, если «с последней подробной записью» означает последнюю на входе, я бы просто использовал шаблон преобразования идентификаторов плюс шаблон, предотвращающий копирование любого Detail, не являющегося последним из его группы, определеннойключ:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:key name="policy" match="Detail" use="PolicyNumber" />

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

  <xsl:template match="Detail[not(generate-id() = generate-id(key('policy', PolicyNumber)[last()]))]"/>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / 3NSSEuP

Если вам нужно отсортировать по RecordID, то в одном шаблоне для первого илиПо последнему пункту группы вы можете отсортировать все элементы в группе и вывести последний по убыванию:

  <xsl:template match="Detail[not(generate-id() = generate-id(key('policy', PolicyNumber)[1]))]"/>

  <xsl:template match="Detail[generate-id() = generate-id(key('policy', PolicyNumber)[1])]">
      <xsl:for-each select="key('policy', PolicyNumber)">
          <xsl:sort select="RecordID" data-type="number" order="descending"/>
          <xsl:if test="position() = 1">
              <xsl:copy-of select="."/>
          </xsl:if>
      </xsl:for-each>
  </xsl:template>

https://xsltfiddle.liberty -development.net / 3NSSEuP / 1 полностью онлайнобразец и имеет

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:key name="policy" match="Detail" use="PolicyNumber" />

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

  <xsl:template match="Detail[not(generate-id() = generate-id(key('policy', PolicyNumber)[1]))]"/>

  <xsl:template match="Detail[generate-id() = generate-id(key('policy', PolicyNumber)[1])]">
      <xsl:for-each select="key('policy', PolicyNumber)">
          <xsl:sort select="RecordID" data-type="number" order="descending"/>
          <xsl:if test="position() = 1">
              <xsl:copy-of select="."/>
          </xsl:if>
      </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>
0 голосов
/ 09 октября 2019

Я бы сделал это так:

XSLT 1.0

<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:key name="policy" match="Detail" use="PolicyNumber" />

<xsl:template match="/*">
    <xsl:copy>
        <xsl:copy-of select="Header"/>
        <!-- for each distinct policy -->
        <xsl:for-each select="Detail[count(. | key('policy', PolicyNumber)[1]) = 1]">
            <!-- sort current group -->
            <xsl:for-each select="key('policy', PolicyNumber)">
                <xsl:sort select="RecordID" data-type="number" order="descending"/>
                <!-- return the record with highest RecordID -->
                <xsl:if test="position() = 1">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet> 
...