1

在一个节点中,一个字符串可能包含一个或多个由单引号或双引号分隔的子字符串。例如

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

我要做的是小写没有被引号包围的文本,所以结果应该如下所示:

some text "and Some" more

我尝试了两件事:

  1. with replacereplace('Some text "and Some" More', '"([^"]*)"', '*')这将用 * 替换双引号中的文本。但是我怎么能小写呢?这不会产生预期的结果:replace('Some text "and Some" More', '"([^"]*)"', lower-case('$1'))
  2. tokenizefor $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

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

在 XPath 3中,您可以使用 ! 简单的地图运算符(有点像 for,除了它设置 . 和 position()):

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