xml XSLT - 从模板中删除空格

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1468984/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 12:45:55  来源:igfitidea点击:

XSLT - remove whitespace from template

xmlxslt

提问by Robert DeBoer

I am using XML to store a small contact list and trying to write a XSL template that will transform it into a CSV file. The problem I am having is with whitespace in the output.

我正在使用 XML 来存储一个小的联系人列表,并尝试编写一个 XSL 模板,将其转换为 CSV 文件。我遇到的问题是输出中有空格。

The output:

输出:

Friend, John, Smith, Home,
        123 test,
       Sebastopol,
       California,
       12345,
     Home 1-800-123-4567, Personal [email protected]

I have indented/spaced both the source XML file and the associated XSL Template to make it easier to read and develop, but all that extra white space is getting itself into the output. The XML itself doesn't have extra whitespace inside the nodes, just outside of them for formatting, and the same goes for the XSLT.

我对源 XML 文件和相关的 XSL 模板都进行了缩进/间隔,以使其更易于阅读和开发,但所有额外的空白都将自己放入输出中。XML 本身在节点内部没有额外的空白,只是在它们外部用于格式化,XSLT 也是如此。

In order for the CSV file to be valid, each entry needs to be on it's own line, not broken up. Besides stripping all extra white space from the XML and XSLT (making them just one long line of code), is there another way to get rid of the whitespace in the output?

为了使 CSV 文件有效,每个条目都需要在它自己的行上,而不是分解。除了从 XML 和 XSLT 中去除所有额外的空格(使它们只是一行长代码)之外,还有另一种方法可以去除输出中的空格吗?

Edit: Here is a small XML sample:

编辑:这是一个小的 XML 示例:

<PHONEBOOK>
    <LISTING>
        <FIRST>John</FIRST>
        <LAST>Smith</LAST>
        <ADDRESS TYPE="Home">
            <STREET>123 test</STREET>
            <CITY>Sebastopol</CITY>
            <STATE>California</STATE>
            <ZIP>12345</ZIP>
        </ADDRESS>
        <PHONE>1-800-123-4567</PHONE>
        <EMAIL>[email protected]</EMAIL>
        <RELATION>Friend</RELATION>
    </LISTING>
</PHONEBOOK>

And here is the XSLT:

这是 XSLT:

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />

 <xsl:template match="/">
   <xsl:for-each select="//LISTING">
    <xsl:value-of select="RELATION" /><xsl:text>, </xsl:text>
    <xsl:value-of select="FIRST" /><xsl:text>, </xsl:text>
    <xsl:value-of select="LAST" /><xsl:text>, </xsl:text>

    <xsl:if test="ADDRESS">
     <xsl:for-each select="ADDRESS">
       <xsl:choose>
        <xsl:when test="@TYPE">
         <xsl:value-of select="@TYPE" />,
        </xsl:when>
            <xsl:otherwise>
            <xsl:text>Home </xsl:text>
            </xsl:otherwise>
       </xsl:choose>
       <xsl:value-of select="STREET" />,
       <xsl:value-of select="CITY" />,
       <xsl:value-of select="STATE" />,
       <xsl:value-of select="ZIP" />,
     </xsl:for-each>
    </xsl:if>

    <xsl:for-each select="PHONE">
      <xsl:choose>
       <xsl:when test="@TYPE">
        <xsl:value-of select="@TYPE" />  
       </xsl:when>
       <xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise>
      </xsl:choose>
     <xsl:value-of select="."  /><xsl:text  >, </xsl:text>
    </xsl:for-each>

    <xsl:if test="EMAIL">
     <xsl:for-each select="EMAIL">
      <xsl:choose>
       <xsl:when test="@TYPE">
        <xsl:value-of select="@TYPE" /><xsl:text  > </xsl:text> 
       </xsl:when>
       <xsl:otherwise><xsl:text  >Personal </xsl:text></xsl:otherwise>
      </xsl:choose>
      <xsl:value-of select="."  /><xsl:text  >, </xsl:text>
     </xsl:for-each>
    </xsl:if>
    <xsl:text>&#10;&#13;</xsl:text>
   </xsl:for-each>
 </xsl:template>

</xsl:stylesheet>

回答by Tomalak

In XSLT, white-space is preserved by default, since it can very well be relevant data.

在 XSLT 中,默认情况下保留空白,因为它很可能是相关数据。

The best way to prevent unwanted white-space in the output is not to create it in the first place. Don't do:

防止输出中出现不需要的空白的最佳方法是首先不要创建它。不要这样做:

<xsl:template match="foo">
  foo
</xsl:template>

because that's "\n··foo\n", from the processor's point of view. Rather do

因为那是"\n··foo\n",从处理器的角度来看。而是做

<xsl:template match="foo">
  <xsl:text>foo</xsl:text>
</xsl:template>

White-space in the stylesheet is ignored as long as it occurs between XML elements only. Simply put: never use "naked" text anywhere in your XSLT code, always enclose it in an element.

样式表中的空白只要出现在 XML 元素之间就会被忽略。简单地说:永远不要在 XSLT 代码中的任何地方使用“裸”文本,始终将其包含在一个元素中。

Also, using an unspecific:

此外,使用不特定的:

<xsl:apply-templates />

is problematic, because the default XSLT rule for text nodes says "copy them to the output". This applies to "white-space-only" nodes as well. For instance:

是有问题的,因为文本节点的默认 XSLT 规则说“将它们复制到输出”。这也适用于“仅空白”节点。例如:

<xml>
  <data> value </data>
</xml>

contains three text nodes:

包含三个文本节点:

  1. "\n··"(right after <xml>)
  2. "·value·"
  3. "\n"(right before </xml>)
  1. "\n··"(紧接着<xml>
  2. "·value·"
  3. \n"(就在之前</xml>

To avoid that #1 and #3 sneak into the output (which is the most common reason for unwanted spaces), you can override the default rule for text nodes by declaring an empty template:

为了避免 #1 和 #3 潜入输出(这是不需要空格的最常见原因),您可以通过声明一个空模板来覆盖文本节点的默认规则:

<xsl:template match="text()" />

All text nodes are now muted and text output must be created explicitly:

所有文本节点现在都被静音,并且必须显式创建文本输出:

<xsl:value-of select="data" />

To remove white-space from a value, you could use the normalize-space()XSLT function:

要从值中删除空格,您可以使用normalize-space()XSLT 函数:

<xsl:value-of select="normalize-space(data)" />

But careful, since the function normalizes any white-space found in the string, e.g. "·value··1·"would become "value·1".

但要小心,因为该函数对字符串中找到的任何空格进行规范化,例如"·value··1·"将变为"value·1".

Additionally you can use the <xsl:strip-space>and <xsl:preserve-space>elements, though usually this is not necessary (and personally, I prefer explicit white-space handling as indicated above).

此外,您可以使用<xsl:strip-space><xsl:preserve-space>元素,尽管通常这不是必需的(而且就我个人而言,我更喜欢如上所述的显式空白处理)。

回答by Noah Heldman

By default, XSLT templates have <xsl:preserve-space>set, which will keep whitespace in your output. You can add <xsl:strip-space elements="*">to tell it to where to delete whitespace.

默认情况下,XSLT 模板已<xsl:preserve-space>设置,这将在您的输出中保留空格。您可以添加<xsl:strip-space elements="*">以告诉它删除空格的位置。

You may also need to include a normalize-space directive, like so:

您可能还需要包含一个 normalize-space 指令,如下所示:

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

Here is an example for preserve/strip space from W3 Schools.

这是W3 Schools 中保留/剥离空间示例

回答by David Andres

As far as removing tabs but retaining separate lines, I tried the following XSLT 1.0 approach, and it works rather well. Your use of version 1.0 or 2.0 largely depends on which platform you're using. It looks like .NET technology is still dependant on XSLT 1.0, and so you're limited to extremely messy templates (see below). If you're using Java or something else, please refer to the much cleaner XSLT 2.0 approach listed towards the very bottom.

至于删除选项卡但保留单独的行,我尝试了以下 XSLT 1.0 方法,并且效果很好。您使用 1.0 或 2.0 版在很大程度上取决于您使用的平台。看起来 .NET 技术仍然依赖于 XSLT 1.0,因此您只能使用极其混乱的模板(见下文)。如果您使用的是 Java 或其他东西,请参考最底部列出的更简洁的 XSLT 2.0 方法。

These examples are meant to be extended by you to meet your specific needs. I'm using tabs here as an example, but this should be generic enough to be extensible.

这些示例旨在由您扩展以满足您的特定需求。我在这里使用选项卡作为示例,但这应该足够通用以便可扩展。

XML:

XML:

<?xml version="1.0" encoding="UTF-8"?>
<text>
        adslfjksdaf

                dsalkfjdsaflkj

            lkasdfjlsdkfaj
</text>

...and the XSLT 1.0 template (required if you use .NET):

...和 ​​XSLT 1.0 模板(如果您使用 .NET,则需要):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet  
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">   
 <xsl:template name="search-and-replace">
   <xsl:param name="input"/>
   <xsl:param name="search-string"/>
   <xsl:param name="replace-string"/>
   <xsl:choose>
    <xsl:when test="$search-string and 
                    contains($input,$search-string)">
       <xsl:value-of
           select="substring-before($input,$search-string)"/>
       <xsl:value-of select="$replace-string"/>
       <xsl:call-template name="search-and-replace">
         <xsl:with-param name="input"
               select="substring-after($input,$search-string)"/>
         <xsl:with-param name="search-string"
               select="$search-string"/>
         <xsl:with-param name="replace-string"
               select="$replace-string"/>
       </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$input"/>
    </xsl:otherwise>
   </xsl:choose>
  </xsl:template>                
  <xsl:template match="text">
   <xsl:call-template name="search-and-replace">
     <xsl:with-param name="input" select="text()" />
     <xsl:with-param name="search-string" select="'&#x9;'" />
     <xsl:with-param name="replace-string" select="''" />
   </xsl:call-template>    
  </xsl:template>
</xsl:stylesheet>

XSLT 2.0 makes this trivial with the replacefunction:

XSLT 2.0 通过以下replace功能使这变得微不足道:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="xs"
      version="2.0">
 <xsl:template match="text">
  <xsl:value-of select="replace(text(), '&#x9;', '')" />
 </xsl:template>
</xsl:stylesheet>

回答by Pavel Minaev

Others have already pointed out the general problem. Specific one for your stylesheet is that you forgot <xsl:text>for commas:

其他人已经指出了普遍的问题。您的样式表的特定之一是您忘记<xsl:text>了逗号:

   <xsl:choose>
    <xsl:when test="@TYPE">
     <xsl:value-of select="@TYPE" />,
    </xsl:when>
    <xsl:otherwise>Home </xsl:otherwise>
   </xsl:choose>
   <xsl:value-of select="STREET" />,
   <xsl:value-of select="CITY" />,
   <xsl:value-of select="STATE" />,
   <xsl:value-of select="ZIP" />,

This makes whitespace following every comma significant, and so it ends up in the output. If you wrap each comma in <xsl:text>, the problem disappears.

这使得每个逗号后面的空格都很重要,因此它最终会出现在输出中。如果将每个逗号括在 中<xsl:text>,问题就会消失。

Also, get rid of that disable-output-escaping. It doesn't do anything here, since you're not outputting XML.

另外,摆脱那个disable-output-escaping。它在这里没有任何作用,因为您没有输出 XML。

回答by Nick Groznykh

My previouse answer is wrong, all commas must be output via tag 'text'

我之前的答案是错误的,所有逗号都必须通过标签“text”输出

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:template match="/PHONEBOOK">
        <xsl:for-each select="LISTING">
            <xsl:value-of select="RELATION" /><xsl:text>, </xsl:text>
            <xsl:value-of select="FIRST" /><xsl:text>, </xsl:text>
            <xsl:value-of select="LAST" /><xsl:text>, </xsl:text>

                <xsl:for-each select="ADDRESS">
                    <xsl:choose>
                        <xsl:when test="@TYPE">
                            <xsl:value-of select="@TYPE" /><xsl:text>,</xsl:text>
                        </xsl:when>
                        <xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise>
                    </xsl:choose>
                <xsl:value-of select="STREET/text()" /><xsl:text>,</xsl:text>
                    <xsl:value-of select="CITY/text()" /><xsl:text>,</xsl:text>
                    <xsl:value-of select="STATE/text()" /><xsl:text>,</xsl:text>
                    <xsl:value-of select="ZIP/text()" /><xsl:text>,</xsl:text>
                </xsl:for-each>

            <xsl:for-each select="PHONE">
                <xsl:choose>
                    <xsl:when test="@TYPE">
                        <xsl:value-of select="@TYPE" />  
                    </xsl:when>
                    <xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise>
                </xsl:choose>
                <xsl:value-of select="."  /><xsl:text  >, </xsl:text>
            </xsl:for-each>

            <xsl:if test="EMAIL">
                <xsl:for-each select="EMAIL">
                    <xsl:choose>
                        <xsl:when test="@TYPE">
                            <xsl:value-of select="@TYPE" /><xsl:text  > </xsl:text> 
                        </xsl:when>
                        <xsl:otherwise><xsl:text  >Personal </xsl:text></xsl:otherwise>
                    </xsl:choose>
                    <xsl:value-of select="."  /><xsl:text  >, </xsl:text>
                </xsl:for-each>
            </xsl:if>
            <xsl:text>&#10;&#13;</xsl:text>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="text()|@*">
        <xsl:text>-</xsl:text>
    </xsl:template>

</xsl:stylesheet>

回答by Tejas Sawant

Modify the code which we used to format raw xml file by removing below lines will remove extra blank white spaces added in exported excel.

通过删除以下行来修改我们用于格式化原始 xml 文件的代码将删除在导出的 excel 中添加的额外空白空格。

While formatting with indented property system is adding those extra blank white spaces.

虽然使用缩进属性系统进行格式化会添加那些额外的空白空格。

Comment lines related to formatting xml like below line and try.

与格式化 xml 相关的注释行如下行并尝试。

xmlWriter.Formatting = System.Xml.Formatting.Indented;

回答by Cylian

This answer may not direct answer to the problem. But a general way solve this issue. Create a template rule:

这个答案可能不会直接回答问题。但是一个通用的方法可以解决这个问题。创建模板规则:

<xsl:template name="strip-space">
    <xsl:param name="data"/>
    <xsl:value-of select="normalize-space($data)"/>
</xsl:template>

Now call it to remove excess white-space:

现在调用它来删除多余的空白:

<xsl:template match="my-element">
    <xsl:call-template name="strip-space">
        <xsl:with-param name="data">
            <xsl:apply-templates/>
        </xsl:with-param>
    </xsl:call-template>
</xsl:template>

For example, consider the below XML fragment:

例如,考虑以下 XML 片段:

<?xml version="1.0" encoding="UTF-8"?>
<test>
    <my-element>
        <e1>some text</e1> <e2>some other text</e2> <e3>some other text</e3>
    </my-element>
</test>

And if someone likes to convert it to below text:

如果有人喜欢将其转换为以下文本:

{test{my-element{e1some text} {e2some other text} {e3some other text}}}

Now comes the stylesheet:

现在是样式表:

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" />

    <xsl:template match="/">
        <xsl:apply-templates mode="t1"/>
        <xsl:text>&#xa;</xsl:text>
        <xsl:apply-templates mode="t2"/>
    </xsl:template>

    <xsl:template match="*" mode="t1">
        <xsl:text>{</xsl:text>
        <xsl:value-of select="local-name()"/>
        <xsl:call-template name="strip-space">
            <xsl:with-param name="data">
                <xsl:apply-templates mode="t1"/>
            </xsl:with-param>
        </xsl:call-template>
        <xsl:text>}</xsl:text>
    </xsl:template>

    <xsl:template match="*" mode="t2">
        <xsl:text>{</xsl:text>
        <xsl:value-of select="local-name()"/>
        <xsl:value-of select="."/>
        <xsl:text>}</xsl:text>
    </xsl:template>

    <xsl:template name="strip-space">
        <xsl:param name="data"/>
        <xsl:value-of select="normalize-space($data)"/>
    </xsl:template>

</xsl:stylesheet>

After applying the stylesheet, it produce:

应用样式表后,它产生:

{test{my-element{e1some text} {e2some other text} {e3some other text}}}

{test

        some text some other text some other text

}

The output describes how @mode="t1"(<xsl:value-of select="."/>approach) differs from the @mode="t2"(xsl:call-templateapproach). Hope this helps somebody.

输出描述了如何@mode="t1"<xsl:value-of select="."/>从接近)不同@mode="t2"xsl:call-template方法)。希望这可以帮助某人。

回答by Nick Groznykh

Add one template into your xslt

将一个模板添加到您的 xslt 中

<xsl:template match="text()"/>