XSLT 是否可以通过脚本或其他方式检测是否存在:
"http://..."
或者
<a>"http..."</a>
在消息字段中并将其样式设置为链接。我已经做好了最坏的打算!
XPath 2.0 提供了 RegEx 处理的宝贵特性。在 XSLT 2.0+ 中使用它可以编写:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vurlRegex"
>(http|https|ftp|mailto)://(\p{L}+\.)+\p{L}+(/\p{L}([./?%&=])*)?</xsl:variable>
<xsl:template match="/*/*[not(matches(.,$vurlRegex))]">
<xsl:sequence select='"Warning:", ., " isn't a valid Uri
"'/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
当此转换应用于以下 XML 文档时:
<t>
<a>http://abc.com</a>
<b>\`\```^^^</b>
</t>
产生了想要的正确结果:
Warning:<b>\`\```^^^</b> isn't a valid Uri
请注意:
使用的 RegEx 可能不是匹配 Url 最精确的 - 您可以用更好和更精确的 RegEx 替换它。
可以用一种更可重用的形式表达这种有用的词法检查,使用xsl:function
:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vurlRegex"
>(http|https|ftp|mailto)://(\p{L}+\.)+\p{L}+(/\p{L}([./?%&=])*)?</xsl:variable>
<xsl:template match="/*/*[not(my:IsValidUrl(.))]">
<xsl:sequence select='"Warning:", ., " isn't a valid Uri
"'/>
</xsl:template>
<xsl:template match="text()"/>
<xsl:function name="my:IsValidUrl" as="xs:boolean">
<xsl:param name="pStr" as="xs:string"/>
<xsl:sequence select="matches($pStr, $vurlRegex)"/>
</xsl:function>
</xsl:stylesheet>
更新:
在这里,我使用了 Michael Kay 在他的评论中提供的表达式引用——这是来自 XSD 工作组发布的 W3C 说明,与 XSD 规范分开:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vurlRegex"
>((([A-Za-z])[A-Za-z0-9+\-\.]*)
:((//(((([A-Za-z0-9\-\._~!$&'()*+,;=:]|(%[0-9A-Fa-f][0-9A-Fa-f]))*@))?
((\[(((((([0-9A-Fa-f]){0,4}:)){6}((([0-9A-Fa-f]){0,4}:([0-9A-Fa-f]){0,4})
|(([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])
|(25[0-5]))\.([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])
|(25[0-5])))))
|(::((([0-9A-Fa-f]){0,4}:)){5}((([0-9A-Fa-f]){0,4}:([0-9A-Fa-f]){0,4})
|(([0-9]|([1-9][0-9])|(1([0-9]){2})
|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})
|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5])))))
|((([0-9A-Fa-f]){0,4})?::((([0-9A-Fa-f]){0,4}:)){4}((([0-9A-Fa-f]){0,4}:([0-9A-Fa-f]){0,4})
|(([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]
|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])
|(25[0-5])))))|(((((([0-9A-Fa-f]){0,4}:))?([0-9A-Fa-f]){0,4}))?::((([0-9A-Fa-f]){0,4}:)){3}((([0-9A-Fa-f]){0,4}:([0-9A-Fa-f]){0,4})
|(([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]
|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})
|(2[0-4][0-9])|(25[0-5])))))|(((((([0-9A-Fa-f]){0,4}:)){0,2}([0-9A-Fa-f]){0,4}))?
::((([0-9A-Fa-f]){0,4}:)){2}((([0-9A-Fa-f]){0,4}:([0-9A-Fa-f]){0,4})|
(([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|
([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})
|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})
|(2[0-4][0-9])|(25[0-5])))))|(((((([0-9A-Fa-f]){0,4}:)){0,3}([0-9A-Fa-f]){0,4}))
?::([0-9A-Fa-f]){0,4}:((([0-9A-Fa-f]){0,4}:([0-9A-Fa-f]){0,4})|(([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})
|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])
|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5])))))
|(((((([0-9A-Fa-f]){0,4}:)){0,4}([0-9A-Fa-f]){0,4}))?::((([0-9A-Fa-f]){0,4}:([0-9A-Fa-f]){0,4})
|(([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})
|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]
|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5])))))
|(((((([0-9A-Fa-f]){0,4}:)){0,5}([0-9A-Fa-f]){0,4}))?::([0-9A-Fa-f]){0,4})
|(((((([0-9A-Fa-f]){0,4}:)){0,6}([0-9A-Fa-f]){0,4}))?::))|(v([0-9A-Fa-f])+\.(([A-Za-z0-9\-\._~]
|[!$&'()*+,;=]|:))+))\])|(([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])
|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5]))\.([0-9]
|([1-9][0-9])|(1([0-9]){2})|(2[0-4][0-9])|(25[0-5])))|(([A-Za-z0-9\-\._~]|(%[0-9A-Fa-f][0-9A-Fa-f])
|[!$&'()*+,;=]))*)((:([0-9])*))?)((/(([A-Za-z0-9\-\._~!$&'()*+,;=:@]|(%[0-9A-Fa-f][0-9A-Fa-f])))*))*)
|(/(((([A-Za-z0-9\-\._~!$&'()*+,;=:@]|(%[0-9A-Fa-f][0-9A-Fa-f])))+((/(([A-Za-z0-9\-\._~!$&'()*+,;=:@]|(%[0-9A-Fa-f][0-9A-Fa-f])))*))*))?)
|((([A-Za-z0-9\-\._~!$&'()*+,;=:@]|(%[0-9A-Fa-f][0-9A-Fa-f])))+((/(([A-Za-z0-9\-\._~!$&'()*+,;=:@]|(%[0-9A-Fa-f][0-9A-Fa-f])))*))*)
|)((\?((([A-Za-z0-9\-\._~!$&'()*+,;=:@]|(%[0-9A-Fa-f][0-9A-Fa-f]))|/
|\?))*))?((#((([A-Za-z0-9\-\._~!$&'()*+,;=:@]|(%[0-9A-Fa-f][0-9A-Fa-f]))|/|\?))*))?)</xsl:variable>
<xsl:template match="/*/*[not(my:IsValidUrl(.))]">
<xsl:sequence select='"Warning:", ., " isn't a valid Uri
"'/>
</xsl:template>
<xsl:template match="text()"/>
<xsl:function name="my:IsValidUrl" as="xs:boolean">
<xsl:param name="pStr" as="xs:string"/>
<xsl:sequence select="matches($pStr, $vurlRegex, 'x')"/>
</xsl:function>
</xsl:stylesheet>