Преобразование в текст в нижний регистр в узлах и дочерних узлах в xsl

Используя xsl 2.0, я пытаюсь преобразовать весь текст в верхнем регистре так, чтобы в каждом верхнем регистре каждого узла была только первая буква текста. У них есть большое количество возможных дочерних элементов.

<text> text text text
<head>BLAH <unkownTag>BLAH</unkownTag> BLAH </head>
</text>

Я хотел бы преобразовать это в чтение

<text> text text text
<head>Blah <unkownTag>Blah</unkownTag> Blah </head>
</text>

Самое близкое, что я пришел, это

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="head/text()">
    <xsl:value-of select="concat(upper-case(substring(.,1,1)),lower-case(substring(.,2)))"/>        
</xsl:template> 

Which gives me the result

<text> text text text 
   <head>Blah <unkownTag>BLAH</unkownTag> blah </head>
</text>

Как я могу добиться, чтобы преобразование в нижний регистр происходило во всех дочерних узлах head?


person user1748728    schedule 27.02.2013    source источник


Ответы (4)


Это преобразование дает желаемый результат без учета знаков препинания, разделяющих слова:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

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

 <xsl:template match="head//text()">
  <xsl:analyze-string select="." regex="\p{{L}}+">
   <xsl:matching-substring>
     <xsl:value-of select=
      "concat(upper-case(substring(.,1,1)), lower-case(substring(.,2)))"/>
   </xsl:matching-substring>
   <xsl:non-matching-substring>
    <xsl:value-of select="."/>
   </xsl:non-matching-substring>
  </xsl:analyze-string>
 </xsl:template>
</xsl:stylesheet>

При применении к предоставленному XML-документу:

<text> text text text
 <head>BLAH <unkownTag>BLAH</unkownTag> BLAH </head>
</text>

Получен желаемый правильный результат:

<text> text text text
 <head>Blah <unkownTag>Blah</unkownTag> Blah </head>
</text>

При применении к этому XML-документу:

<text> text text text
 <head>BLAH$<unkownTag>BLAH</unkownTag>-BLAH;</head>
</text>

снова получается правильный результат:

<text> text text text
 <head>Blah$<unkownTag>Blah</unkownTag>-Blah;</head>
</text>

Объяснение:

  1. Правильное использование инструкции <xsl:analyze-string>.

  2. Правильное использование класса символов \p{L} .

  3. Правильное использование <xsl:matching-substring> и < инструкции href = "http://www.w3.org/TR/xslt20/#element-non-matching-substring" rel = "nofollow"> <xsl:non-matching-substring>.

person Dimitre Novatchev    schedule 27.02.2013

Пробелы в вашем тексте сделали это интересной проблемой. Чтобы сопоставить все узлы text () ниже 'head', используйте выражение XPath для просмотра предка.

Здесь я токенизирую строку, а затем перебираю результирующий набор, меняя первый символ на верхний регистр, а следующие символы - на нижний.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="@*|node()">
       <xsl:copy>
           <xsl:apply-templates select="@*|node()"/>
       </xsl:copy>
   </xsl:template>

   <xsl:template match="text()[ ancestor::head ]">
       <xsl:value-of select="
            for $str in tokenize( ., '\s' ) 
            return concat( upper-case(substring($str,1,1)), 
                           lower-case(substring($str,2)) )"/>
   </xsl:template>
</xsl:stylesheet>
person ljdelight    schedule 27.02.2013

Попробуй это. Я не тестировал его, и вам, возможно, придется немного его настроить.

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

<xsl:template match="head">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()">
      <xsl:value-of select="concat(upper-case(substring(.,1,1)),lower-case(substring(.,2)))"/>
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>
person AdamRox    schedule 27.02.2013
comment
К сожалению, это не похоже на то, что ‹xsl: value-of› разрешено внутри ‹xsl: application-templates›. - person user1748728; 27.02.2013

Это может помочь вам сориентироваться.

<xsl:template match="/">
  <xsl:apply-templates select="node()" mode="firstup"/>
</xsl:template>

<xsl:template match="text()" mode="firstup">
  <!--<x>-->
    <xsl:value-of select="concat(upper-case(substring(.,1,1)),lower-case(substring(.,2)))"/>
  <!--</x>-->
</xsl:template>

Не уверен, что насчет третьего «BLAH», этот узел text () начинается с пробела, поэтому будет немного труднее получить правильное использование заглавных букв в родственных текстовых узлах. Раскомментируйте элемент «x», чтобы увидеть это. Вы также можете посмотреть на нормализацию пробелов и функцию position (), чтобы продвинуться дальше.

person raybiss    schedule 27.02.2013