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



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

属性@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:collapse更改为XSchema的崩溃。

这是接近您想要的东西...

<?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

编辑得好。谢谢迪米特雷。

我不相信我读错了规范,但假设我读错了;让我修复我的例子(也许我应该离开它来找我(。

<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/在这方面是错误的。

你还没有正确理解xml:space的定义。

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

从 XML 1.0 规范:

">

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

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

此资源包含易于理解的 xml:space 属性说明。

更新

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

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

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

我在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=只是测试空格的一种方式。优先级解决了当节点是元素中唯一的文本节点(因此是第一个和最后一个(时引起的冲突。

建立在你之前的答案之上...如果您有如下所示的文件

<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>

最新更新