XSLT 转换带点分隔字符的字符串

XSLT transforming string with dot separated characters

我正在使用 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>

我找到了解决方案:

<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>

您可以使用 RegEx 来 fn:replace 每个字符,字符本身后跟一个点:

  1. 首先,删除所有其他带有translate的字符:

    translate(.,' .,','')
    
  2. 二、将所有字符转为大写:

    upper-case(.)
    
  3. 将每个字符替换为其后跟一个点:

    replace(.,'(.)','.'))
    
  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(.,' .,','')),'(.)','.')),'\.$','')"/></field>
                </account>
            </xsl:for-each>
        </results>
    </xsl:template>

</xsl:stylesheet>

在 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>