在XSLT 1.0中规范化​​混合内容元素中的空格

时间:2012-07-07 04:16:08

标签: xml xslt

[编辑:改变标题以更好地概念化问题。]

属性@xml:space的值可以是"default""preserve"。 XML指定了第二个意味着什么,但是第一个意味着应用程序。 (我认为我有正确的。)那么如果应用程序希望default实现XSchema的collapse怎么办? XSLT 1.0怎么能真正做到这一点?

我认为用于处理文本的内置模板,即

<xsl:template match="text()">
   <xsl:value-of select="."/>
</xsl:template>

需要替换为类似伪代码的东西:

<xsl:choose>
   <xsl:when test="../@xml:space='preserve'"
     <xsl:value-of select="."/>
   </xsl:when>
   <xsl:otherwise>

      if position(.)=1 then output LTRIM(value-of(.))
      if position(.)=last() then output RTRIM(value-of(.))
      if position(.)= 1 and last()=1 then output normalize-space(.)

   </xsl:otherwise>
</xsl:choose>

然后输入:

<persName> The man is 
   <forename>Edward</forename>

   <forename>George</forename>
   <surname type="linked">Bulwer-Lytton</surname>, <roleName>Baron Lytton of
   <placeName>Knebworth</placeName>
   </roleName>
</persName>

The man is Edward George Bulwer-Lytton, Baron Lytton of Knebworth正确呈现,The man之前的空格和Knebworth修剪后EdwardGeorge之间的空格会崩溃。 (这个例子来自TEI。)

[编辑:我在这里删除了一个错误且误导性的段落。]

需要为每个文本节点执行实现该伪代码的XSLT 1.0。难道不是那么丑陋和缓慢吗? [编辑:或许不是。我简化了伪代码。有快速修剪程序吗?选择真的那么慢吗?]

结论:如何在XSLT 1.0中实现XSchema的崩溃(仅使用嵌入浏览器的扩展)?

我希望我说的都是正确的。我希望代码很简单。我还没有看到它是怎么回事。 [编辑:改变xs:崩溃到XSchema崩溃。]

5 个答案:

答案 0 :(得分:0)

这是你想要的东西......

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes"/>
<xsl:strip-space elements="*"/>  

<xsl:template match="/">
Demonstration of collapsed white space.
=======================================
<xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="text()">
  <xsl:value-of select="concat(normalize-space(.),' ')" />  
</xsl:template>

</xsl:stylesheet>

这会产生输出......

Demonstration of collapsed white space.
=======================================
The man is Edward George Bulwer-Lytton , Baron Lytton of Knebworth

答案 1 :(得分:0)

您尚未正确理解xml:space的定义。

它仅适用于仅空白文本节点。它不适用于包含在也具有非空白字符的文本节点中的空白字符(也称为“重要空白空间”)。

来自XML 1.0 Specification

  

另一方面,”重要的“白色空间应该是   保存在交付版本中是常见的,例如在诗歌中   和源代码

因此,“修剪”文本节点的整个想法与xml:space无关。

This resource 包含对xml:space属性的易于理解的解释。

<强>更新

答案中的OP改变了他的初始要求。现在他想要的只是(如果我对他的答案的理解是正确的话)删除所有仅具有相同父级的空白文本节点中的第一个(我也认为是最后一个)仅空白文本节点。

这很简单 - 只需将此模板添加到XSLT样式表

<xsl:template match=
   "text()[not(normalize-space())][position() = 1 or position() = last()]"/>

答案 2 :(得分:0)

好编辑。谢谢Dimitre。

我不相信我正在阅读这个规格错误,但我假设了一下;让我来解决一下我的例子(也许我应该留下它来了)。

<persName>
   <forename>Edward</forename>
   <forename>George</forename>
   <surname type="linked">Bulwer-Lytton</surname>, <roleName>Baron Lytton of
   <placeName>Knebworth</placeName>
   </roleName>
</persName>

我希望默认处理是删除<forename>Edward</forename>之前的仅空白文本节点,而不是<forename>Edward</forename>之后的仅空白文本节点。

但是,我不清楚xml:space仅指包含或删除仅空白文本节点,例如xsl:strip-space。事实上,正如您所指出的,2.10白色空间处理使用诗歌和源代码作为例子。那些是空间在文本节点内的情况。 @xml:space标识应该如何处理该空间。它应该以应用程序的默认方式保存或处理吗?

我认为http://www.xmlplease.com/xml/xmlspace/在这方面是错误的。

答案 3 :(得分:0)

我在xml-dev检查过,结果证明我对@xml:space的含义和用途是正确的。

以下是用于规范混合内容元素中的空白的代码(这是说出我想要做的更好的方式):

<xsl:template priority=".7" match="text()[position()=1 and not((ancestor::node()/@xml:space)[position()=last()]='preserve')]">
    <xsl:value-of select="normalize-space()"/>
    <xsl:if test="normalize-space(substring(., string-length(.))) = ''">
        <xsl:text> </xsl:text>
    </xsl:if>
</xsl:template>
<xsl:template priority=".7" match="text()[position()=last() and not((ancestor::node()/@xml:space)[position()=last()]='preserve')]">
    <xsl:if test="normalize-space(substring(., 1, 1)) = ''">
        <xsl:text> </xsl:text>
    </xsl:if>
    <xsl:value-of select="normalize-space()"/>
</xsl:template>
<xsl:template priority=".8" match="text()[position()=1 and position()=last() and not((ancestor::node()/@xml:space)[position()=last()]='preserve')]" >
    <xsl:value-of select="normalize-space(.)"/>
</xsl:template>

@xml:space上的过滤允许preserve覆盖。 test=只是测试空白的一种方法。优先级解决了当节点是元素中唯一的文本节点时产生的冲突,从而解决了第一个和最后一个节点之间的冲突。

答案 4 :(得分:0)

以您之前的答案为基础......如果您的文件看起来像这样

<document>
<p>A paragraph of text with subtags (whitespace after; no whitespace only between): Lorem
        <italic>Before/After</italic> dolor sit amet, consectetur adipiscing elit, sed do eiusmod
    tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim <italic>Before/After</italic>
    quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<p>A paragraph of text with subtags (whitespace between: Lorem ipsum dolor sit amet, consectetur
    adipiscing elit, sed do eiusmod <italic>Before/After</italic>
    <italic>Before/After</italic> incididunt ut labore et dolore magna aliqua. Ut enim ad minim
    veniam, <italic>Before/After</italic> <italic>Before/After</italic> laboris nisi ut aliquip 
    ex ea commodo consequat. </p>
</document>

然后,斜体标签之间的位不会被规范化空间模板捕获,因为它们既不在块的开头也不在块的末尾。

据我所知,你必须添加第四个来检查打开和关闭空间(并保留它),然后将这些内容标准化。

<xsl:template priority=".7" match="text()[not(position()=1) and not(position()=last()) 
    and not((ancestor::node()/@xml:space)[position()=last()]='preserve')]" >
    <xsl:if test="normalize-space(substring(., 1, 1)) = ''">
        <xsl:text> </xsl:text>
    </xsl:if>
        <xsl:value-of select="normalize-space()"/>
    <xsl:if test="normalize-space(substring(., string-length(.), 1)) = ''">
        <xsl:text> </xsl:text>
    </xsl:if>
</xsl:template>