Xslt 仅从父元素修剪空白

Xslt 仅从父元素修剪空白,xslt,whitespace,trim,Xslt,Whitespace,Trim,我想修剪XML中p标记中的前导空格,因此: <p> Hey, <em>italics</em> and <em>italics</em>!</p> …它分别应用于每个文本节点(括号中),并将其吸干: [Hey,]<em>[italics]</em>[and]<em>[italics]</em>[!] [嘿,][斜体][和][斜体][!] 我的XSLT基本上如下所示: &

我想修剪XML中p标记中的前导空格,因此:

<p>  Hey, <em>italics</em> and <em>italics</em>!</p>
…它分别应用于每个文本节点(括号中),并将其吸干:

[Hey,]<em>[italics]</em>[and]<em>[italics]</em>[!]
[嘿,][斜体][和][斜体][!]
我的XSLT基本上如下所示:

<xsl:template match="p">
    <xsl:apply-templates/>
</xsl:template>
<xsl:template match="p">
    <xsl:apply-templates/>
</xsl:template>

<!-- strip leading whitespace -->
<xsl:template match="p/node()[1][self::text()]">
  <xsl:call-template name="left-trim">
     <xsl:with-param name="s" value="."/>
  </xsl:call-template>
</xsl:template>


那么,有没有什么方法可以让应用模板完成,然后在输出上运行normalize space,这样做应该是正确的呢

 <xsl:template match="text()">
  <xsl:value-of select=
   "substring(
       substring(normalize-space(concat('[',.,']')),2),
       1,
       string-length(.)
              )"/>
 </xsl:template>


这会将字符串包装到
“[]”
,然后执行
normalize-string()
,最后删除包装字符。

我会这样做:

<xsl:template match="p">
    <xsl:apply-templates/>
</xsl:template>
<xsl:template match="p">
    <xsl:apply-templates/>
</xsl:template>

<!-- strip leading whitespace -->
<xsl:template match="p/node()[1][self::text()]">
  <xsl:call-template name="left-trim">
     <xsl:with-param name="s" value="."/>
  </xsl:call-template>
</xsl:template>
如果您还想去除尾随空格,正如标题可能暗示的那样,请添加以下两个模板:

<!-- strip trailing whitespace -->
<xsl:template match="p/node()[last()][self::text()]">
  <xsl:call-template name="right-trim">
     <xsl:with-param name="s" value="."/>
  </xsl:call-template>
</xsl:template>

<!-- strip leading/trailing whitespace on sole text node -->
<xsl:template match="p/node()[position() = 1 and
                              position() = last()][self::text()]"
              priority="2">
   <xsl:value-of select="normalize-space(.)"/>
</xsl:template>

左修剪和右修剪模板的定义位于(未测试)。对于包含大量
的文档,它们的速度可能较慢。如果可以使用XSLT2.0,则可以将调用模板替换为

  <xsl:value-of select="replace(.,'^\s+','')" />


(感谢。)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="p//text()[1][generate-id()=
                                      generate-id(ancestor::p[1]
                                                  /descendant::text()[1])]">
        <xsl:variable name="vFirstNotSpace"
                      select="substring(normalize-space(),1,1)"/>
        <xsl:value-of select="concat($vFirstNotSpace,
                                     substring-after(.,$vFirstNotSpace))"/>
    </xsl:template>
</xsl:stylesheet>

输出:

<p>Hey, <em>italics</em> and <em>italics</em>!</p>
<p><b>Hey, </b><em>italics</em> and <em>italics</em>!</p>
嘿,斜体字和斜体字

编辑2:更好的表达式(现在只有三个函数调用)

编辑3:匹配第一个子体文本节点(如果是文本节点,则不只是第一个节点)。感谢@Dimitre的评论

现在,有了这个输入:

<p><b>  Hey, </b><em>italics</em> and <em>italics</em>!</p>
嘿,斜体字和斜体字

输出:

<p>Hey, <em>italics</em> and <em>italics</em>!</p>
<p><b>Hey, </b><em>italics</em> and <em>italics</em>!</p>
嘿,斜体字和斜体字


问得好+1.有关简单的解决方案,请参见我的答案。:)+一个好问题。请看我的答案,我认为这是目前为止唯一一个符合你要求的答案。你的意思是只前导空格,还是前导和尾随?你能给出一个你想要实现的输出的例子吗?现在还不清楚。您只是想删除第一个text()节点的前导空格吗?换句话说,只保留“嘿”之前的空格,并保留文本节点的尾随空格以及围绕“和”?@Mads:围绕什么和什么?(降价问题)+1我认为它并没有完全达到@jpatokal想要的效果,但它还没有被清楚地表述出来。这提供了从
p/text()[1]
中修剪前导空格所需的所有信息,这是我认为需要的。@LarsH:回答得好。我想你不是想要
p/node()[1][self::text()]
而是想要
p/node()[self::text()][1]
。最后一个文本节点也是如此。@Dimitre:这不是(a)产生第一个/最后一个文本节点,不管它们是否在任何非文本子节点的“外部”;或者(b)做和我一样的事?请进一步解释,因为我想更好地理解这一点。@Mads,如果p/text()[1]前面有一个元素,如
a
,我认为他不想从
p/text()[1]
中删除前导空格,是吗?但我同意,让@jpatokal澄清一下。@LarsH:
p/node()[1][self::text()]
的意思是:p的第一个节点子节点,但前提是它是文本节点。而您想要的是:
p
的所有文本节点子节点中的第一个,我相信方括号用于演示它当前正在做什么(从每个文本节点中去掉前导和尾随空格)。这无法实现所需的输出(尚未明确说明)。@Mads Hansen:如果包装字符仅用于说明目的(这似乎是可能的),则可以在应用
normalize-space()
后将其删除。我更新了我的答案,做到了这一点,我想这就是OP想要的。这是目前为止唯一一个规范化文本节点内部空白的答案。这个想法很有趣,但我担心它实际上不起作用——当我尝试时,我得到了“嘿,]斜体和斜体!”?但是+1对于其他答案的有用评论。哇:-)我想我看到了嵌套的substring()调用在做什么,它比递归模板好得多+1@Alejandro:我想你作为拉尔斯有smae问题。我想你不想
p/node()[1][self::text()]
而是
p/node()[self::text()][1]
。@Dimitre:那和
p/text()[1]
一样,但我知道你的意思。+1我想我们有赢家了!这就是我所理解的期望输出。非常好的解决方案。@Alejandro:不完全是,考虑一下:
你好

。这将是:
(p//text())[1]
<p><b>Hey, </b><em>italics</em> and <em>italics</em>!</p>