XSLT: объединение двух последовательных элементов до тех пор, пока список элементов не станет пустым - PullRequest
0 голосов
/ 15 октября 2019

У меня есть этот XML

<participants>
  <event>Seminar</event>
  <location>City somewhere</location>
  <first_name>Carl</first_name>
  <last_name>Smith</last_name>
  <first_name>John</first_name>
  <last_name>Somebody</last_name>
  <first_name>Lisa</first_name>
  <last_name>Lint</last_name>
  <first_name>Gabriella</first_name>
  <last_name>Whowho</last_name>
</participants>

Который мне нужно преобразовать в это:

<participants>
  <event>Seminar</event>
  <location>City somewhere</location>
  <persons>
     <person>
        <given_name>Carl</given_name>
        <surname>Smith</surname>
    </person>
    <person>
        <given_name>John</given_name>
        <surname>Somebody</surname>
    </person>
    <person>
        <given_name>Lisa</given_name>
        <surname>Lint</surname>
    </person>
    <person>
        <given_name>Gabriella</given_name>
        <surname>Whowho</surname>
    </person>
  </persons>
</participants>

Число людей может быть любым числом, иногда могут быть пустые элементы(Если имя и фамилия будут пустыми, то этот человек не будет создан.

Мне трудно начать с этим преобразованием.

1 Ответ

0 голосов
/ 15 октября 2019

Если вы просто обрабатываете элементы first_name и используете XPath-навигацию, чтобы выбрать его родного брата last_name, вы получите

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

  <xsl:output indent="yes"/>

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

  <xsl:template match="participants">
      <xsl:copy>
          <xsl:apply-templates select="*[not(self::first_name | self::last_name)]"/>
          <xsl:apply-templates select="first_name" mode="person"/>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="first_name" mode="person">
      <xsl:variable name="surname" select="following-sibling::last_name[1]"/>
      <xsl:if test="normalize-space() and normalize-space($surname)">
          <person>
              <xsl:apply-templates select=". | $surname"/>
          </person>
      </xsl:if>
  </xsl:template>

  <xsl:template match="first_name">
      <given_name>
          <xsl:apply-templates/>
      </given_name>
  </xsl:template>

  <xsl:template match="last_name">
      <surname>
          <xsl:apply-templates/>
      </surname>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / 94AbWAW / 1

...