Java 如何使用XSLT v1.0插入文本,而不是使用XSLT v2.0正则表达式?
我有一个xml文件,它用描述完全限定java类名的属性值来描述(除其他外)元素。我试图编写一个XSLT转换来修改这个文件中描述的类名,例如,Java 如何使用XSLT v1.0插入文本,而不是使用XSLT v2.0正则表达式?,java,xml,regex,xslt,Java,Xml,Regex,Xslt,我有一个xml文件,它用描述完全限定java类名的属性值来描述(除其他外)元素。我试图编写一个XSLT转换来修改这个文件中描述的类名,例如,com.example.MyClass的ocurrance将变成com.example.MockMyClass 下面是在原始文件片段的上下文中再次出现的示例: <event type="node-enter"> <action name="MyActionName" class="com.example.MyClass">
com.example.MyClass
的ocurrance将变成com.example.MockMyClass
下面是在原始文件片段的上下文中再次出现的示例:
<event type="node-enter">
<action name="MyActionName" class="com.example.MyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
是一个开始,但我需要在匹配的字符串中插入文本,而不仅仅是替换
以下是我的正则表达式(XSLT 2.0)尝试,以供参考:
嘲弄
以下内容如何
<xsl:template name="classname">
<xsl:param name="class"/>
<xsl:choose>
<xsl:when test="contains($class,'.')">
<xsl:value-of select="concat(substring-before($class,'.'),'.')"/>
<xsl:call-template name="classname">
<xsl:with-param name="class"
select="substring-after($class,'.')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('Mock',$class)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
它将类名作为输入参数,并在最后的“.”之后添加“Mock”。例如,你可以用
<xsl:call-template name="classname">
<xsl:with-param name="class" select="@class"/>
</xsl:call-template>
(我只是在Firefox中快速试用了一下,你可能会发现你需要整理一些空白。)下面的内容似乎很长,但是它使用了现成的部分(strRev
模板由FXSL提供,不需要重新编写)。此外,将近一半的代码是标识模板,并将参数传递给
。这在XSLT2.0中被大大缩短了
当我们准备好更小的部件/函数,比如strRev
template/reverse()
函数时,这个解决方案就不需要编写长时间且容易出错的自制递归代码
基本思想是字符串中的最后一个。
字符是反向字符串中的第一个。
字符
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pPrepend" select="'Mock'"/>
<xsl:variable name="vRevPrepend">
<xsl:call-template name="strRev">
<xsl:with-param name="pText" select="$pPrepend"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="action/@class">
<xsl:variable name="vRevText">
<xsl:call-template name="strRev"/>
</xsl:variable>
<xsl:variable name="vRevNew" select=
"concat(substring-before($vRevText,'.'), $vRevPrepend,
'.', substring-after($vRevText,'.'))"/>
<xsl:variable name="vNewText">
<xsl:call-template name="strRev">
<xsl:with-param name="pText" select="$vRevNew"/>
</xsl:call-template>
</xsl:variable>
<xsl:attribute name="class">
<xsl:value-of select="$vNewText"/>
</xsl:attribute>
</xsl:template>
<xsl:template name="strRev">
<xsl:param name="pText" select="."/>
<xsl:if test="string-length($pText)">
<xsl:call-template name="strRev">
<xsl:with-param name="pText" select="substring($pText,2)"/>
</xsl:call-template>
<xsl:value-of select="substring($pText,1,1)"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的XML文档时:
<event type="node-enter">
<action name="MyActionName" class="com.example.MyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
<event type="node-enter">
<action name="MyActionName" class="com.example.MockMyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
<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"/>
<xsl:param name="pPrepend" select="'Mock'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="action/@class">
<xsl:attribute name="class" select=
"my:strRev(concat(substring-before(my:strRev(.),'.'),
my:strRev($pPrepend),'.',
substring-after(my:strRev(.),'.')
)
)
"/>
</xsl:template>
<xsl:function name="my:strRev" as="xs:string">
<xsl:param name="pText" as="xs:string"/>
<xsl:sequence select=
"codepoints-to-string(reverse(string-to-codepoints($pText)))
"/>
</xsl:function>
</xsl:stylesheet>
模板/MyTemplate.vm
生成所需的正确结果:
<event type="node-enter">
<action name="MyActionName" class="com.example.MyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
<event type="node-enter">
<action name="MyActionName" class="com.example.MockMyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
<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"/>
<xsl:param name="pPrepend" select="'Mock'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="action/@class">
<xsl:attribute name="class" select=
"my:strRev(concat(substring-before(my:strRev(.),'.'),
my:strRev($pPrepend),'.',
substring-after(my:strRev(.),'.')
)
)
"/>
</xsl:template>
<xsl:function name="my:strRev" as="xs:string">
<xsl:param name="pText" as="xs:string"/>
<xsl:sequence select=
"codepoints-to-string(reverse(string-to-codepoints($pText)))
"/>
</xsl:function>
</xsl:stylesheet>
模板/MyTemplate.vm
II。XSLT 2.0解决方案:
<event type="node-enter">
<action name="MyActionName" class="com.example.MyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
<event type="node-enter">
<action name="MyActionName" class="com.example.MockMyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
<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"/>
<xsl:param name="pPrepend" select="'Mock'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="action/@class">
<xsl:attribute name="class" select=
"my:strRev(concat(substring-before(my:strRev(.),'.'),
my:strRev($pPrepend),'.',
substring-after(my:strRev(.),'.')
)
)
"/>
</xsl:template>
<xsl:function name="my:strRev" as="xs:string">
<xsl:param name="pText" as="xs:string"/>
<xsl:sequence select=
"codepoints-to-string(reverse(string-to-codepoints($pText)))
"/>
</xsl:function>
</xsl:stylesheet>
完全相同的算法,但在XSLT 2.0中非常简短:
<event type="node-enter">
<action name="MyActionName" class="com.example.MyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
<event type="node-enter">
<action name="MyActionName" class="com.example.MockMyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
<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"/>
<xsl:param name="pPrepend" select="'Mock'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="action/@class">
<xsl:attribute name="class" select=
"my:strRev(concat(substring-before(my:strRev(.),'.'),
my:strRev($pPrepend),'.',
substring-after(my:strRev(.),'.')
)
)
"/>
</xsl:template>
<xsl:function name="my:strRev" as="xs:string">
<xsl:param name="pText" as="xs:string"/>
<xsl:sequence select=
"codepoints-to-string(reverse(string-to-codepoints($pText)))
"/>
</xsl:function>
</xsl:stylesheet>
@Ryan,你的正则表达式中的$
是用来做什么的?若它应该匹配行尾或字符串尾,那个么它不会失败吗,因为它后面必须跟一个字母数字?如果是这样的话,这似乎是多余的。但也许我误解了。@LarsH的$
是为了迎合内部类,例如com.example.MyClass$internal
。但是我现在看到这个正则表达式也会匹配一个字符串,比如com$example.MyClass
,所以如果我继续使用正则表达式解决方案,我需要修复这个错误。@Ryan Bennetts:您需要通过
和$
标记吗?或者只是通过
?@Ryan好的,谢谢。我忘了[]
中的$
是一个文本。内部类使用了$
符号+1。请注意,对于类名不包含
的基本情况,它会给出不同的结果,但是这种情况在实践中可能不会发生。+1-您可以通过在
中包装文本节点,而不是在模板中“裸”挂起,来避免一些空白问题。这样,您就可以格式化代码,而不必担心模板中的回车符和其他空格会潜入到输出中。只有在空白字符前面或后面有非空白字符时,空白字符才被视为有效字符。用
换行将用于输出的文本内容与格式化空白区分开。谢谢,我不知道这一点。@Matthw Wilson:+1回答得好。这不处理内部类,例如com.example.MyClass$internal
,但这在现阶段对我来说并不重要。我很难找到正确的上下文来调用您的模板,但最终通过匹配上的“action/@class”
并使用
调用模板找到了答案,谢谢!我不能说我已经完全掌握了您的代码,但是看起来您已经硬编码了“MockMyClass”作为转换后的类名。然而,我想做的是在类名前面加上“Mock”一词,这样-例如-com.example.ExampleClass
变成com.example.MockExampleClass
或com.example.AnotherExampleClass
当然了,这是最简单的事情——只需等待20分钟即可。:)谢谢Dimitre,你的代码运行得很好,但我还是选择了Matthew Wilson的解决方案,因为它更简洁。@Ryan Bennetts:作为一个消费者,它对你来说应该是一样的,但是如果你是一个开发人员,我的解决方案是一种可以节省大量时间和错误的设计模式——您只需使用现成的函数/模板,无需编写自己的递归代码。字符串反转正是解决路径/content/art/VO1113VIEW05.01.tif
问题的方法,我需要在路径中去掉.tif
,而不是.05.tif
。