1

ノード内の文字列には、一重引用符または二重引用符で区切られた 1 つ以上の部分文字列が含まれる場合があります。例えば

<node>Some text "and Some" More</node>

私がしなければならないことは、引用符で囲まれていないテキストを小文字にすることです。結果は次のようになります。

some text "and Some" more

私は2つのことを試しました:

  1. with replace:replace('Some text "and Some" More', '"([^"]*)"', '*')これにより、二重引用符内のテキストが * に置き換えられます。しかし、どうすれば小文字にできますか?これは望ましい結果を生み出しません:replace('Some text "and Some" More', '"([^"]*)"', lower-case('$1'))
  2. tokenize: for $t in tokenize('Some text "and Some" More', '"') return $t。私のノードは" で始まらないため、奇数のエントリは引用符で囲まれた部分文字列になることがわかっています。しかし、奇数のエントリのみを選択して小文字にする方法がわかりません。試してみましposition()たが、反復ごとに 1 が返されます。 .

ご検討いただきありがとうございます。とても有難い。

4

3 に答える 3

1

ふぅ。

あなたがそれを難し​​い方法で望む場合:

concat(translate(substring-before(//node/text(), '"'),'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') ,substring(substring-after(//node/text(), '"'), 1, string-length(substring-after(//node/text(), '"')) - string-length(substring-after(substring-after(//node/text(), '"'), '"')) -1) , translate(substring-after(substring-after(//node/text(), '"'), '"'), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))

//node/text()必要なテキストに到達するXPathに置き換えるだけです。私はただ楽しみのためにこれをしました、これは「最もきれいな」(HA!)解決策ではありません。

配置されたノードがコンテキストノードであることを確認するか、より直接的なパスを指定することで、高速化できます。

于 2013-03-13T19:44:18.310 に答える
1

以下は、引用符で囲まれた文字列と引用符で囲まれていない文字列の任意の組み合わせ (任意の順序) を目的の方法で処理する単一の XPath 2.0 式です

  string-join(
  (for $str in tokenize(replace(., "(.*?)("".*?"")([^""]*)", "|$1|$2|$3|", "x"),"\|")
     return
      if(not(contains($str, """")))
        then lower-case($str)
        else $str
  ),
  "")

包括的なテストのために、次の XML ドキュメントで上記の式を評価します。

<node>Some "Text""and Some" More "Text" XXX "Even More"</node>

必要な正しい結果が生成されます。

some "Text""and Some" more "Text" xxx "Even More"

XSLT 2.0 検証:

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

 <xsl:template match="/">
  <xsl:sequence select=
  'string-join(
  (for $str in tokenize(replace(., "(.*?)("".*?"")([^""]*)", "|$1|$2|$3|", "x"),"\|")
     return
      if(not(contains($str, """")))
        then lower-case($str)
        else $str
  ),
  "")
  '/>
 </xsl:template>
</xsl:stylesheet>

この変換が上記の XML ドキュメントに適用されると、XPath 式が評価され、この評価の結果が出力にコピーされます

some "Text""and Some" more "Text" xxx "Even More"

最後に、XSLT 2.0 ソリューション -- 記述と理解がはるかに簡単です。

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

 <xsl:template match="/*">
  <xsl:analyze-string select="." regex='".*?"'>
   <xsl:non-matching-substring>
     <xsl:sequence select="lower-case(.)"/>
   </xsl:non-matching-substring>
   <xsl:matching-substring><xsl:sequence select="."/></xsl:matching-substring>
  </xsl:analyze-string>
 </xsl:template>
</xsl:stylesheet>
于 2013-03-14T05:53:41.940 に答える
1

XQueryでは、使用できます

string-join(
  for $x at $i  in tokenize('Some text "and Some" More', '"') return
    if ($i mod 2 = 1) then lower-case($x)
    else $x
  , '"')

しかし、xpath には at なしで不自由な for しかありません。

XPath 3では、! 単純なマップ演算子 (. と position() を設定することを除いて、for のようなものです):

string-join(
  tokenize('Some text "and Some" More', '"') !
    if (position() mod 2 = 1) then lower-case(.)
    else .
  , '"')

最後に、XPath 2では、インデックスを反復処理して、各インデックスの部分文字列を取得できます。

string-join(
  for $i in 1 to count(tokenize('Some text "and Some" More', '"')) return
    if ($i mod 2 = 1) then lower-case(tokenize('Some text "and Some" More', '"')[$i])
    else tokenize('Some text "and Some" More', '"')[$i]
  , '"')
于 2013-03-13T20:54:51.603 に答える