【问题标题】:How to create reusable function to lower-camel-case text?如何为小写字母文本创建可重用函数?
【发布时间】:2014-07-16 00:11:53
【问题描述】:

我正在尝试创建一个函数,它将我碰巧选择的任何文本都小写,无论是节点的纯文本值(“UserRole”)还是属性的值(“UserRoleInfo”)。这是示例数据:

<className>UserRole</className>         <!-- Want to create text userRole -->

<fieldGroups>
    <fieldGroup name="UserRoleInfo"/>   <!-- Want to create text userRoleInfo -->
</fieldGroups>

如果您想提供解决方案,无需进一步阅读。但是,如果您有兴趣,这是我尝试实现这样的事情。

在这里,我选择类名:

<xsl:apply-templates mode="lowerCaseName" select="/className"/>

这里,我选择的是属性:

<xsl:apply-templates mode="printFieldGroupAssignments" select="/fieldGroups"/>

<xsl:template mode="printFieldGroupAssignments" match="fieldGroups">
    <xsl:for-each select="./fieldGroup">
        <xsl:apply-templates mode="lowerCaseName" select="./attribute::name"/>
    </xsl:for-each>
</xsl:template>

所以这是我的“可重用函数”,它应该接受一个节点或一个属性。

<xsl:template mode="lowerCaseName" match="node()">
    <xsl:value-of select="concat(lower-case(substring(.,1,1)), substring(.,2))"/>
</xsl:template>
<xsl:template mode="lowerCaseName" match="attribute()">
    <xsl:value-of select="concat(lower-case(substring(.,1,1)), substring(.,2))"/>
</xsl:template>

我收到以下错误:

[ERROR]: 'attribute()' 中的语法错误。

[错误]:文件:Entity.xsl:第 849 行:解析 XPath 表达式“attribute()”时出错。

所以我把attribute()改为text()

<xsl:template mode="lowerCaseName" match="text()">
    <xsl:value-of select="concat(lower-case(substring(.,1,1)), substring(.,2))"/>
</xsl:template>

我收到以下错误:

[错误]:无法编译样式表

[致命]:错误检查表达式'funcall(小写,[funcall(substring,[cast(variable-ref(entityClassName/node-set),string),cast(int-expr(1))的类型, real), cast(int-expr(1), real)])])'。

我认为我的问题是我不了解节点、节点集和纯旧文本之间的区别。

解决此问题的下一步应该是什么?我应该放弃并用不同的方法重新开始吗?欢迎所有建议。

【问题讨论】:

    标签: xml xslt xpath xslt-2.0 xpath-2.0


    【解决方案1】:

    我认为我的问题是我不了解其中的区别 在节点、节点集和纯旧文本之间。

    这些是重要的区别。恕我直言,这里还有两个可能更相关:(1)函数与命名模板和(2)应用模板与调用模板。

    关于 #1,您说您想创建一个函数,但您正在编写模板。
    关于 #2,您正在使用 mode 应用模板,您应该在其中调用 命名模板

    要使用命名模板执行此操作,您需要定义一个模板,例如:

    <xsl:template name="lowerFirst">
        <xsl:param name="text"/>
        <xsl:value-of select="concat(lower-case(substring($text, 1, 1)), substring($text, 2))"/>
    </xsl:template>
    

    然后根据需要调用它。例如,给定以下测试输入

    <root>
        <anything>AnyThing</anything>
        <!-- leave as is -->
    
        <className name="TestCase">UserRole</className>
        <!-- Want to create text userRole -->
    
        <fieldGroups>
            <fieldGroup name="UserRoleInfo"/>
            <!-- Want to create text userRoleInfo -->
        </fieldGroups>
    </root>
    

    您可以使用以下样式表:

    XSLT 2.0

    <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template name="lowerFirst">
        <xsl:param name="text"/>
        <xsl:value-of select="concat(lower-case(substring($text, 1, 1)), substring($text, 2))"/>
    </xsl:template>
    
    <xsl:template match="className">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:call-template name="lowerFirst">
                <xsl:with-param name="text" select="."/>
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="fieldGroup/@name">
        <xsl:attribute name="name">
            <xsl:call-template name="lowerFirst">
                <xsl:with-param name="text" select="."/>
            </xsl:call-template>
        </xsl:attribute>
    </xsl:template>
    
    </xsl:stylesheet>
    

    获得:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
          <anything>AnyThing</anything>
       <!-- leave as is -->
    
        <className name="TestCase">userRole</className>
       <!-- Want to create text userRole -->
    
        <fieldGroups>
                <fieldGroup name="userRoleInfo"/>
          <!-- Want to create text userRoleInfo -->
        </fieldGroups>
    </root>
    

    --
    在 XSLT 2.0 中,您可以创建自己的函数并使用它来代替命名模板,例如:

    XSLT 2.0

    <xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:my="http://www.example.com/my"
    exclude-result-prefixes="my">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:function name="my:lowerFirst">
        <xsl:param name="text"/> 
        <xsl:value-of select="concat(lower-case(substring($text, 1, 1)), substring($text, 2))"/>
    </xsl:function>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="className">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:value-of select="my:lowerFirst(.)"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="fieldGroup/@name">
        <xsl:attribute name="name">
            <xsl:value-of select="my:lowerFirst(.)"/>
        </xsl:attribute>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • XSLT 2.0 允许将&lt;xsl:attribute name="name"&gt;&lt;xsl:value-of select="my:lowerFirst(.)"/&gt;&lt;/xsl:attribute&gt; 写为&lt;xsl:attribute name="name" select="my:lowerFirst(.)"/&gt;
    • @michael 根据XSLT Fiddle,您的两个示例的输出都是&lt;?xml version="1.0" encoding="UTF-8"?&gt;AnyThing&lt;!-- leave as is --&gt;&lt;classname xmlns="http://www.w3.org/1999/xhtml" name="TestCase"&gt;userRole&lt;/classname&gt;&lt;!-- Want to create text userRole --&gt;&lt;!-- Want to create text userRoleInfo --&gt;。我没有看到它改变了 UserRoleInfo。它不会产生您在上面列出的输出。
    • @michael xmlns:my="http://www.example.com/my" 给出“URI 未注册”的错误,它告诉我添加架构或 DTD。
    • @michael exclude-result-prefixes="my" 做什么?
    • @PatrickGarner XSLT Fiddle 的“无框架”处理器似乎无法正常运行。与 Saxon 一起尝试,可在此处和以下地址获取:xslttest.appspot.com
    【解决方案2】:

    你已经写了 match="attribute()"。如果你想匹配任何属性,通常的方式是match="@*",但如果你愿意,你也可以(在2.0中)写match="attribute(*)"。如错误消息所示,您的语法不被允许。

    这只是其他人给你的好答案的一个小补充。

    【讨论】:

    • 这很有帮助。 xsl:version 显示 1.0。使用 saxon9he.jar 给出输出 2.0。所以,现在,可以使用match="attribute()"
    • 我刚刚意识到我的代码没有正确标记并且没有显示星号,尽管它在那里 - 很抱歉造成任何混淆。
    • attribute(*) 中的星号是必需的吗?你去哪里上网看参考资料? W3Schools 给我留下了深刻的印象,而且 MDN 似乎主要关注 JS 和 DOM。
    • 抱歉,我错了:星号是可选的。我在考虑需要它的函数(*)。权威的XPath语法在这里:w3.org/TR/xpath20/#nt-bnf,相关产生式是[60] AttributeTest ::= "attribute" "("(AttribNameOrWildcard ("," TypeName)?)? ")"
    猜你喜欢
    • 1970-01-01
    • 2013-02-04
    • 2023-03-24
    • 2022-11-27
    • 1970-01-01
    • 2014-07-04
    • 2015-08-07
    • 2020-08-24
    • 2019-01-15
    相关资源
    最近更新 更多