Строка преобразования XSLT с разделенными точками символами - PullRequest
0 голосов
/ 21 января 2020

Я использую XSLT для преобразования XML. Я хочу разделить символы узла initials точками:

Следующие вещи, которые мне нужно изменить на initials:

  1. Все символы разделены точкой
  2. Прописать каждый символ
  3. Удалить пробелы

Я не могу найти способ разделить символы и вставить точки, если они не существуют.

<?xml version="1.0" encoding="UTF-8"?>
<jsonObject>
    <account>
        <initials>ABC</initials>
    </account>
    <account>
        <initials>A BC</initials>
    </account>
    <account>
        <initials>A.B.C  </initials>
    </account>
    <account>
        <initials>a.B.C</initials>
    </account>
</jsonObject>

Я хочу следующий вывод после преобразования:

<results>
   <account>
      <field name="initials">A.B.C</field>
   </account>
   <account>
      <field name="initials">A.B.C</field>
   </account>
   <account>
      <field name="initials">A.B.C</field>
   </account>
   <account>
      <field name="initials">A.B.C</field>
   </account>
</results>

моя таблица стилей до сих пор:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="/*">
        <results>
            <xsl:for-each select="account">
                <account>
                    <field name="initials"><xsl:value-of select="upper-case(translate(initials, ' ',''))"/></field>
                </account>
            </xsl:for-each>
        </results>
    </xsl:template>

</xsl:stylesheet>

Ответы [ 3 ]

0 голосов
/ 21 января 2020

Вы можете использовать RegEx'ы для fn: заменить каждый символ на сам символ, за которым следует точка:

  1. Сначала удалите все остальные символы с помощью translate:

    translate(.,' .,','')
    
  2. Во-вторых, переведите все символы в верхний регистр:

    upper-case(.)
    
  3. Замените каждый символ на себя, за которым следует точка:

    replace(.,'(.)','$1.'))
    
  4. Удалить начальные и конечные пробелы:

    normalize-space(.)
    
  5. Удалить последнюю точку:

    replace(.,'\.$','')
    

Это код XSLT-2.0:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="/*">
        <results>
            <xsl:for-each select="account">
                <account>
                    <field name="initials"><xsl:value-of select="replace(normalize-space(replace(upper-case(translate(.,' .,','')),'(.)','$1.')),'\.$','')"/></field>
                </account>
            </xsl:for-each>
        </results>
    </xsl:template>

</xsl:stylesheet>
0 голосов
/ 21 января 2020

В XSLT 3.0 вы можете использовать функцию analyze-string:

  <xsl:template match="initials">
      <xsl:copy>
          <xsl:value-of
            select="analyze-string(., '\p{L}')/*:match => string-join('.') => upper-case()"/>
      </xsl:copy>
  </xsl:template>

https://xsltfiddle.liberty-development.net/pPJ9hE3

Или вы можете использовать XSLT 2/3 xsl:analyze-string элемент в функции, аналогичный вашему подходу:

<xsl:stylesheet 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"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all"
    version="2.0">


  <xsl:function name="mf:analyze">
      <xsl:param name="input" as="xs:string"/>
      <xsl:param name="regex" as="xs:string"/>
      <xsl:analyze-string select="$input" regex="{$regex}">
          <xsl:matching-substring>
              <fn:match>
                  <xsl:value-of select="."/>
              </fn:match>
          </xsl:matching-substring>
      </xsl:analyze-string>
  </xsl:function>

  <xsl:template match="initials">
      <xsl:copy>
          <xsl:value-of
            select="upper-case(
                      string-join(
                         mf:analyze(., '\p{L}'),
                         '.'
                      )
                    )"/>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
0 голосов
/ 21 января 2020

я нашел решение:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:functx="http://www.functx.com"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:function name="functx:chars" as="xs:string*" xmlns:functx="http://www.functx.com">
        <xsl:param name="arg" as="xs:string?"/>

        <xsl:sequence select="
            for $ch in string-to-codepoints($arg)
            return codepoints-to-string($ch)
            "/>

    </xsl:function>

    <xsl:template match="/*">
        <results>
            <xsl:for-each select="account">
                <account>
                    <field name="initials"><xsl:value-of select="string-join(functx:chars(upper-case(translate(translate(initials, '.',''), ' ',''))), '.')"/></field>                    
                </account>
            </xsl:for-each>
        </results>
    </xsl:template>

</xsl:stylesheet>
...