【问题标题】:Reference an attribute/parameter in a regex expression在正则表达式中引用属性/参数
【发布时间】:2017-07-06 08:07:45
【问题描述】:

我有两种类型的 xml 文件(pom.xml 和描述符),我想将它们加入到单个数据集中。没有公用键,所以我取这两个目录,并在下划线前使用项目名称片段。

我有两个变量可以使用:

repository="/home/qeebrato/Git/ddt"
uri="file:/home/qeebrato/Git/ddt/eventhandlers_repeatlookup/src/main/resources/descriptors/eventhandlers_repeatlookup.descriptor"

我想要“事件处理程序”。

为了得到这个项目片段,我有

<xsl:attribute name="project"><xsl:value-of select='replace(@uri,"(.*)@repository(^_).*_(^$)","$2")'/></xsl:attribute>

我看到的有关 XSLT 字符串处理的网页没有提到在正则表达式中使用标识符。

【问题讨论】:

  • 要替换或标记化的正则表达式参数只是字符串,因此您可以将它们构造为任何其他字符串,例如concat 如果您想基于其他字符串和变量或节点的组合来构建它们。
  • concat 解决方法做到了,谢谢。我仍然不确定是否可以在 XSLT 中转义字符串以包含属性/变量?
  • 我不明白为什么concat 是一种解决方法。如果您迁移到 XSLT/XPath 3,您还可以使用 || 运算符,例如'foo' || @uri || 'bar' w3.org/TR/xpath-30/#id-string-concat-expr,但没有 PHP 的“foo$varbar”形式的字符串插值。

标签: regex xslt xslt-2.0


【解决方案1】:

构建要在 replace() 正则表达式中使用的字符串

replace() 函数至少需要三个参数:输入字符串、要匹配的正则表达式模式和替换。

在您的示例中: * 输入字符串是某个元素的uri 属性。 * 该模式似乎包含同一元素上的repository 属性的值。 * 替换只是模式中的第二个匹配项。

您在帖子中提到的主要问题在于模式——您希望包含 repository 属性的值。为此,我们可以按照 Martin Honnen 评论中的建议,使用concat() 构造字符串:

concat("(.*)", @repository, "(^_).*_(^$)")

解决正则表达式问题

我创建了一个简单的测试 XML 文档:

<?xml version="1.0" encoding="UTF-8"?>
<test repository="/home/qeebrato/Git/ddt" uri="file:/home/qeebrato/Git/ddt/eventhandlers_repeatlookup/src/main/resources/descriptors/eventhandlers_repeatlookup.descriptor"/>

还有一个简单的 XSL 文件应用到这个测试,使用上面固定的 replace() 调用:

<xsl:template match="test">
    <xsl:value-of select='replace(@uri,concat("(.*)", @repository, "(^_).*_(^$)"),"$2")'/>
</xsl:template>

针对这个 XML 运行这个 XSL 可以得到:

file:/home/qeebrato/Git/ddt/eventhandlers_repeatlookup/src/main/resources/descriptors/eventhandlers_repeatlookup.descriptor

...这与uri 属性的原始值相同。最终,你的replace() 什么都不做。

来自the W3C specification

摘要:该函数返回xs:string,该$input 的每个非重叠子字符串与给定的$pattern 匹配,替换为$replacement 字符串的出现。

仔细阅读本文并进行测试,发现如果$pattern 有效,但不匹配任何内容,该函数将返回$input

让我们解构你的 $pattern 正则表达式。

  • (.*) -- 零个或多个字符:
    仅此一项就可以匹配整个字符串。
  • @repository -- repository 属性的值:/home/qeebrato/Git/ddt
    这与 $input 字符串中实际路径的第一部分匹配。
  • (^_) -- 这就是有趣的地方。
    认为您的意思是使用 [^_] 代替,方括号表示不是下划线的字符。
    但是,带有圆括号的(^_) 转换为在$input 的开头或行首的下划线的捕获匹配,具体取决于您的模式。 replace() 函数默认为 ^ 匹配整个字符串的开头。由于$input 字符串的开头没有下划线,因此此$pattern 无法匹配——因此该函数按原样返回$input

得到你需要的东西

你说,我想要“事件处理程序”。如果您的意思是,我想提取字符串的这一部分,这是您需要将其作为输出的replace 语句:

replace(@uri, concat(".*", @repository, "/([^_]+)_.*$"), "$1")

分解:

  • .* 匹配零个或多个字符。
  • @repository 插入该属性的字符串值:/home/qeebrato/Git/ddt
  • /,因为我们需要另一个路径分隔符。
  • ([^_]+) 在圆括号中捕获,我们捕获的是+ 一个或多个[^_] 不是下划线的字符。
  • _.*$ 匹配以下下划线,然后匹配其他任何内容,直到字符串结尾。

我们用$1 替换所有这些,这是我们第一个(也是唯一一个)捕获的匹配,产生eventhandlers

注意事项

  • 您在帖子中提到您有两个变量。但是,您在 replace() 调用中使用了 @ 符号,它指定了一个属性值。

    如果repositoryuri 实际上是变量(在您的XSL 中使用&lt;xsl:variable&gt; 元素定义)或参数(使用&lt;xsl:param&gt; 定义),那么您需要使用$ 而不是@

  • 如果您经常使用正则表达式,那么使用正则表达式工具可能会非常值得,例如Regex Tester(在线)、RegExr(在线)或RegexBuddy(付费应用程序;显然是由维护http://www.regular-expressions.info/ 的同一个人制作的)。

    (完全披露:我已经使用 RegexBuddy 多年,但与任何这些正则表达式网站或工具开发商都没有关系)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-25
    • 2013-03-16
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 2012-10-03
    • 2011-01-04
    相关资源
    最近更新 更多