Как мне исправить мой XSLT, чтобы правильно переводить XML в HTML, как ожидалось? - PullRequest
0 голосов
/ 30 мая 2020

Я использую XSLT для преобразования XML в HTML.

XML это:

<PARA>
    1050
    <EMPH STYLE="min_max">
        <EMPH HL="LOW">-50</EMPH>
        <EMPH HL="HIGH">+50</EMPH>
    </EMPH>
     min
    <EMPH BOLD="0" HL="HIGH" ITAL="0" SMALLCAPS="0">-1</EMPH>
</PARA>

Как правильно визуализировать вывод как:

1050 -50 +50 min<sup>-1</sup>

В настоящее время я получаю 1050 min -50 +50 <sup>-1</sup>

Мой XSLT:

<xsl:template match="PARA"> 
    <xsl:value-of select="text()"/>
    <xsl:choose>
        <xsl:when test="EMPH">
            <xsl:apply-templates select="EMPH"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>

<xsl:template match="EMPH">
    <xsl:choose>
        <xsl:when test="@BOLD=1"><b><xsl:value-of select="."/></b></xsl:when>
        <xsl:when test="@HL='HIGH'"><sup><xsl:value-of select="."/></sup></xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="."/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Ответы [ 2 ]

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

Я бы попытался обработать атрибуты с помощью рекурсивного шаблона и сохранить сопоставление имен атрибутов с HTML элементами на карте (в XSLT, поддерживаемом с Saxon 9.8, вы можете использовать карту XPath 3.1, но в XSLT 2, если вы необходимо использовать эту довольно старую версию Saxon, вы, конечно, можете определить некоторую переменную, содержащую структуру XML, отображающую имена, например, <map><att name="BOLD">b</att></map>):

  <xsl:param name="att-map" as="map(xs:string, xs:string)"
    select="map { 'BOLD' : 'b', 'HL' : 'sup', 'ITAL' : 'i' }"/>

  <xsl:template match="PARA">
      <p>
          <xsl:apply-templates/>
      </p>
  </xsl:template>

  <xsl:template match="EMPH[@STYLE = 'min_max']/EMPH">
      <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="EMPH">
      <xsl:param name="atts" select="@*[. = ('1', 'HIGH')]"/>
      <xsl:choose>
          <xsl:when test="head($atts)">
              <xsl:element name="{$att-map(local-name(head($atts)))}">
                  <xsl:apply-templates select=".">
                      <xsl:with-param name="atts" select="tail($atts)"/>
                  </xsl:apply-templates>
              </xsl:element>
          </xsl:when>
          <xsl:otherwise>
              <xsl:apply-templates/>
          </xsl:otherwise>
      </xsl:choose>
  </xsl:template>

https://xsltfiddle.liberty-development.net/jxDjims/1

Я также использовал функции XSLT / XPath 3 head и tail, но вы, конечно, можете использовать эквиваленты XPath 2 subsequence или $atts[1] и $atts[position() gt 1].

Другой вариант - написать шаблоны для атрибутов, которые вы хотите преобразовать:

  <xsl:param name="att-map" as="map(xs:string, xs:string)"
    select="map { 'BOLD' : 'b', 'HL' : 'sup', 'ITAL' : 'i' }"/>

  <xsl:template match="PARA">
      <p>
          <xsl:apply-templates/>
      </p>
  </xsl:template>

  <xsl:template match="EMPH[@STYLE = 'min_max']/EMPH" priority="5">
      <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="@BOLD[. = 1] | @ITAL[. = 1] | @HL[. = 'HIGH']">
      <xsl:param name="atts"/>
      <xsl:element name="{$att-map(local-name())}">
          <xsl:choose>
              <xsl:when test="$atts">
                  <xsl:apply-templates select="head($atts)">
                      <xsl:with-param name="atts" select="tail($atts)"/>
                  </xsl:apply-templates>
              </xsl:when>
              <xsl:otherwise>
                  <xsl:apply-templates select="../node()"/>
              </xsl:otherwise>
          </xsl:choose>
      </xsl:element>
  </xsl:template>

  <xsl:template match="EMPH[@*[. = ('1', 'HIGH')]]">
      <xsl:apply-templates select="head(@*[. = ('1', 'HIGH')])">
          <xsl:with-param name="atts" select="tail(@*[. = ('1', 'HIGH')])"/>
      </xsl:apply-templates>
  </xsl:template>

  <xsl:mode on-no-match="text-only-copy"/>

https://xsltfiddle.liberty-development.net/jxDjims/2

Как я предполагаю, SMALLCAPPS не может быть преобразован с помощью простой атрибут для карты имени элемента, это также может помочь написать еще несколько шаблонов для большей гибкости, ниже используется базовый шаблон для рекурсивной обработки, он вызывается с <xsl:next-match/> другим, более специализированным шаблоном es, описывающие преобразование атрибутов в элементы:

  <xsl:param name="att-map" as="map(xs:string, xs:string)"
    select="map { 'BOLD' : 'b', 'HL' : 'sup', 'ITAL' : 'i' }"/>

  <xsl:template match="PARA">
      <p>
          <xsl:apply-templates/>
      </p>
  </xsl:template>

  <xsl:template match="EMPH[@STYLE = 'min_max']/EMPH" priority="5">
      <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="@BOLD[. = 1] | @ITAL[. = 1] | @HL[. = 'HIGH']" mode="attributes-to-elements">
      <xsl:element name="{$att-map(local-name())}">
          <xsl:next-match/>
      </xsl:element>
  </xsl:template>

  <xsl:template match="@SMALLCAPS[. = 1]" mode="attributes-to-elements">
      <span style="font-variant: small-caps">
          <xsl:next-match/>
      </span>
  </xsl:template>

  <xsl:template match="@*" mode="attributes-to-elements">
      <xsl:param name="remaining-atts" tunnel="yes"/>
      <xsl:choose>
          <xsl:when test="$remaining-atts">
              <xsl:apply-templates select="head($remaining-atts)" mode="#current">
                  <xsl:with-param name="remaining-atts" tunnel="yes" select="tail($remaining-atts)"/>
              </xsl:apply-templates>
          </xsl:when>
          <xsl:otherwise>
              <xsl:apply-templates select="../node()"/>
          </xsl:otherwise>
      </xsl:choose>      
  </xsl:template>

  <xsl:template match="EMPH[@*[. = ('1', 'HIGH')]]">
      <xsl:apply-templates select="head(@*[. = ('1', 'HIGH')])" mode="attributes-to-elements">
          <xsl:with-param name="remaining-atts" tunnel="yes" select="tail(@*[. = ('1', 'HIGH')])"/>
      </xsl:apply-templates>
  </xsl:template>

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

В конце, может быть проще выполнить двухэтапное преобразование, которое сначала нормализует input вы должны удалить любые атрибуты, не указывающие на какой-то особый стиль или упаковку HTML, а также преобразовать атрибуты в нормализованные элементы, тогда на втором шаге можно будет проще использовать обычный apply-templates на основе элементов, чтобы просто преобразовать вложенный ввод в вложенный HTML.

0 голосов
/ 30 мая 2020

Я обнаружил, что это работает:

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

<xsl:template match="EMPH">
    <xsl:choose>
        <xsl:when test="@BOLD=1"><b><xsl:value-of select="text()"/></b></xsl:when>
        <xsl:when test="@HL='HIGH'"><sup><xsl:value-of select="text()"/></sup></xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="."/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Я хотел бы знать, есть ли лучший способ обработки нескольких атрибутов элемента EMPH, чем <xsl:choose>, потому что таким образом у меня для обработки всех комбинаций как уникальных <xsl:when> проверок.

Например, я должен проверять «жирный», «надстрочный» и «жирный и надстрочный» как три разных предложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...