Мне нужно преобразовать все имена элементов в XML в стратегию именования camelCase с помощью XSLT.
Вот ответ от грядущего сервера:
<ROOT_ELEMENT>
<ELEMENT_1>2595959584</ELEMENT_1>
<Element_Two>Lorem</Element_Two>
<eLement_Three>Ipsum</eLement_Three>
<BIRTH_date>
<Day>21</Day>
<Month>09</Month>
<Year>1955</Year>
</BIRTH_date>
</ROOT_ELEMENT>
Вот что я хочу преобразовать:
<rootElement>
<element1>2595959584</element1>
<elementTwo>Lorem</elementTwo>
<elementThree>Ipsum</elementThree>
<birthDate>
<day>21</day>
<month>09</month>
<year>1955</year>
</birthDate>
</rootElement>
Любая помощь приветствуется.





В XSLT 3.0 это
string-join(tokenize(name(), '_') !
(upper-case(substring(., 1, 1)) || lower-case(substring(., 2))))
В 1.0 это намного сложнее, но все же возможно (по крайней мере, если ваши имена элементов используют только буквы ASCII). Вам понадобится рекурсивный именованный шаблон для выполнения токенизации (вы можете найти его в http://www.exslt.org, ищите str:tokenize в модуле строк), а в именованном шаблоне, где вы обрабатываете один токен, вам нужно будет использовать translate($x, 'abc...z', 'ABC...Z') для выполнения конверсия случая.
Вы можете избежать рекурсии и упростить логику, если знаете, что в имени будет только одно подчеркивание; в этом случае вы можете использовать substring-before() и substring-after(), чтобы получить две части имени.
Я не готов писать код XSLT 1.0 для такой задачи, это абсолютно неинтересно. Перейдите к более поздней версии, и такие люди, как я, с большей вероятностью предложат помощь.
На самом деле, в XSLT 3.0 тоже сложнее: приведенное выше вернет PascalCase, а требование для camelCase (первый символ в нижнем регистре).
Предполагая, что в имени элемента будет не более одного разделителя _ и если имена не содержат символов, отличных от ASCII, вы можете использовать:
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:strip-space elements = "*"/>
<xsl:template match = "*">
<xsl:param name = "upper-case" select = "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:param name = "lower-case" select = "'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name = "name" select = "name()" />
<xsl:variable name = "word2" select = "substring-after($name, '_')" />
<xsl:variable name = "new-name">
<xsl:value-of select = "translate(substring-before(concat($name, '_'), '_'), $upper-case, $lower-case)"/>
<xsl:value-of select = "translate(substring($word2, 1, 1), $lower-case, $upper-case)"/>
<xsl:value-of select = "translate(substring($word2, 2), $upper-case, $lower-case)"/>
</xsl:variable>
<xsl:element name = "{$new-name}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Если (как кажется) вы используете процессор, поддерживающий функцию расширения XSLT str:tokenize(), вы можете сделать:
XSLT 1.0 + EXSLT
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:str = "http://exslt.org/strings"
extension-element-prefixes = "str">
<xsl:output method = "xml" version = "1.0" encoding = "UTF-8" indent = "yes"/>
<xsl:strip-space elements = "*"/>
<xsl:template match = "*">
<xsl:param name = "upper-case" select = "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:param name = "lower-case" select = "'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name = "new-name">
<xsl:for-each select = "str:tokenize(name(), '_')">
<xsl:choose>
<xsl:when test = "position() = 1">
<xsl:value-of select = "translate(., $upper-case, $lower-case)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select = "translate(substring(., 1, 1), $lower-case, $upper-case)"/>
<xsl:value-of select = "translate(substring(., 2), $upper-case, $lower-case)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<xsl:element name = "{$new-name}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Это снимает ограничение на количество разделителей _, которые может иметь имя элемента. Остается другое ограничение: в параметрах $upper-case и $lower-case должен быть указан каждый возможный символ, который может встречаться в имени элемента и иметь варианты в верхнем и нижнем регистре.
Еще один способ сделать первую букву в XSLT 1.0 заглавной:
<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "xml" indent = "yes" />
<xsl:variable name = "smallcase" select = "'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name = "uppercase" select = "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:template match = "*">
<xsl:variable name = "convertElementName">
<xsl:choose>
<xsl:when test = "contains(local-name(.),'_')">
<xsl:value-of
select = "concat(translate(substring-before(local-name(.),'_'), $uppercase, $smallcase),
translate(substring(substring-after(local-name(.),'_'),1,1), $smallcase, $uppercase),
translate(substring(substring-after(local-name(.),'_'),2,string-length(local-name(.))-1), $uppercase, $smallcase))" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select = "translate(local-name(.), $uppercase, $smallcase)" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name = "{$convertElementName}">
<xsl:apply-templates select = "@* | node()" />
</xsl:element>
</xsl:template>
<xsl:template match = "@*">
<xsl:attribute name = "{local-name(.)}">
<xsl:value-of select = "." />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
<xsl:template match = "*">
<xsl:choose>
<xsl:when test = "contains(name(), '_')">
<xsl:element name = "{concat(substring-before(lower-case(name()), '_'), substring(substring-after(upper-case(name()), '_'), 1,1), substring(substring-after(lower-case(name()), '_'), 2))}">
<xsl:apply-templates/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name = "{lower-case(name())}">
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Еще один ответ, если возможно, используйте этот код.
Этот вопрос помечен как XSLT 1.0. Ваш ответ требует XSLT 2.0.
Откуда взялась строчная функция? Я получил эту ошибку. javax.xml.transform.TransformerException: не удалось найти функцию: нижний регистр
Этот ответ был XSLT 2.0
Спасибо за ответ. Но я только сегодня познакомился с XSLT. Я еще ничего не знал о XSLT. Есть ли полное решение этой проблемы.