【问题标题】:XSLT: can I limit the application of template and 'connect' it to some apply-template call?XSLT:我可以限制模板的应用并将其“连接”到某些应用模板调用吗?
【发布时间】:2014-12-09 18:16:08
【问题描述】:

据我所知,XSL 的工作原理如下:它选择一些节点进行处理,然后应用于此选择中的每个节点。

我很困惑,因为看起来在这里我们有两次相同的 SOMETHING 选择:首先在应用模板中,然后在模板匹配中。请考虑我下面的例子。我得到了我想要的:仅当文本属性不为空时,才用 Pmatch 标签替换项目中的标签。但是如你所见,我已经两次指定了这个条件!这是正常的方式吗?

XML

<?xml version="1.0" encoding="UTF-8"?>
<Manager text="this is a manager">
    <Name text="true name">Ivan</Name>
    <Projects text="ps">
        <Project text="ba">Bank</Project>
        <Project text="ca">Cars</Project>
        <Project>Business</Project>
    </Projects>
</Manager>

XSL

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:foo="myFoo" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/Manager">
        <ThisIsWhatIWantToSeeInName>
            <xsl:apply-templates/>
        </ThisIsWhatIWantToSeeInName>
    </xsl:template>
    <xsl:template match="Name">
        <NewName>Rihanna</NewName>
    </xsl:template>
    <xsl:template match="Projects">
        <Jobs>Jo-Jobs</Jobs>
        <NewJobs>
        <xsl:apply-templates select="Project[@text != '']"/>
        </NewJobs>
    </xsl:template>
    <xsl:template match="Project[@text != '']">
        <PMatch><xsl:value-of select="@text"/></PMatch>
    </xsl:template>
</xsl:stylesheet>

结果:

<?xml version="1.0" encoding="UTF-8"?>
<ThisIsWhatIWantToSeeInName xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:foo="myFoo" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <NewName>Rihanna</NewName>
    <Jobs>Jo-Jobs</Jobs>
    <NewJobs>
        <PMatch>ba</PMatch>
        <PMatch>ca</PMatch>
    </NewJobs>
</ThisIsWhatIWantToSeeInName>

为了逃避双重选择规范,我尝试了以下方法:

1) 我尝试通过选择所有 Proejct 来扩大应用模板的选择范围。 但是,当模板仅找到那些具有文本属性的模板时 - 其他模板会发送到默认模板,这会在我的 XML 中产生一些纯文本。我能以某种方式影响这种行为吗?我可以关闭默认模板吗?

2) 我尽量限制应用模板的选择。好的,但是如果我现在让模板匹配更广泛,比如 match='/'(因为在 apply-templates 中选择了所有正确的节点) - 我的模板将在这部分代码之前匹配许多元素,它甚至会匹配根节点。可能是,我可以以某种方式将我的模板“连接”到应用它的地方?我想确保我的模板只在我想要的地方被调用。

【问题讨论】:

    标签: xml xslt xpath


    【解决方案1】:

    你可以做的是从 xsl:apply-templates` 中删除条件,

    <xsl:apply-templates select="Project"/>
    

    那么你会有两个这样的模板

    <xsl:template match="Project[@text != '']">
        <PMatch><xsl:value-of select="@text"/></PMatch>
    </xsl:template>
    
    <xsl:template match="Project" />
    

    因为第一个模板指定了条件,所以它比没有条件的模板具有更高的优先级,这意味着它总是会首先得到匹配。这意味着具有非空 @text 属性的 Project 元素将按预期获得输出。因此,第二个模板将只匹配具有空 @text 属性的 Project 元素(或根本不匹配 @text 属性)。

    如果你愿意,你可以颠倒逻辑

    <xsl:template match="Project">
        <PMatch><xsl:value-of select="@text"/></PMatch>
    </xsl:template>
    
    <xsl:template match="Project[not(@text) or @text = '']" />
    

    注意,不一定要写第二个模板如下:

    <xsl:template match="Project[@text = '']" />
    

    这只会匹配存在@text 属性(并且设置为空字符串)的Project 元素。它不会匹配没有属性的 Project 元素。

    【讨论】:

      【解决方案2】:

      如果您只是将模板应用于带有谓词的项目,则无需在 match 属性中重复谓词。所以你的最后一个模板可能只是:

      <xsl:template match="Project">
          <PMatch><xsl:value-of select="@text"/></PMatch>
      </xsl:template>
      

      请注意上述关于选择性应用模板的条件。如果不加选择地应用模板,则会调用内置模板并得到垃圾文本。

      【讨论】:

        猜你喜欢
        • 2022-08-18
        • 1970-01-01
        • 2016-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多