XSL保留XML CDATA中的空间

时间:2015-01-31 01:24:17

标签: xml xslt whitespace

我尝试了各种解决方案,但似乎无法实现这一目标。

我正在进行XML到XML(FOP)的XSL转换以进行PDF创建。源XML具有< code>内容以CDATA声明开头的元素。转换会删除换行符。

示例输入XML:

<?xml version="1.0" encoding="iso-8859-1"?>
<myxml>
    <code><![CDATA[import java.nio.charset.Charset;
    import com.my.library.AClass;
    import com.my.library.AnotherClass;

    public String getStringValue(String key) {
            // Just some ramblings

            // Dummy code...
            if (key != null && key.length() > 0) {
                System.out.println(key);
            }
        }
    ]]></code>
</myxml>

示例XSL:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns="http://www.w3.org/TR/xhtml1/strict" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    exclude-result-prefixes="fo" 
    >
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" cdata-section-elements="code"/>
<xsl:preserve-space elements="code" />

<fo:block font-family="Courier New" font-size="12pt" color="black" 
    space-after="12pt" space-before="12pt" space-before.precedence="4">

      <fo:block>
          <xsl:text>Copy</xsl:text>
          <xsl:copy>
            <xsl:value-of select="code"/>
          </xsl:copy>
      </fo:block>

      <fo:block>
          <xsl:text>Copy Text</xsl:text>
          <xsl:copy>
            <xsl:value-of select="code/text()"/>
          </xsl:copy>
      </fo:block>

      <fo:block>
          <xsl:text>Original</xsl:text>
          <xsl:value-of select="code"/>
      </fo:block>

      <fo:block>
          <xsl:text>Normalise space</xsl:text>
          <value-of select="normalize-space(code)" disable-output-escaping="yes"/>
      </fo:block>

      <fo:block>          
          <xsl:text>Copy with extra CDATA wrapper?</xsl:text>
          <xsl:copy>
            <xsl:text disable-output-escaping="yes"><![CDATA[<![CDATA[]]></xsl:text>
            <xsl:value-of select="code"/>
            <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
          </xsl:copy>         
      </fo:block>

      <fo:block>
        <xsl:text>Again, an attempt to wrap</xsl:text>
        <xsl:text disable-output-escaping="yes">
          &lt;![CDATA[
        </xsl:text>
        <xsl:value-of select="code" />
        <xsl:text disable-output-escaping="yes">
          ]]&gt;
        </xsl:text>
      </fo:block>
</fo:block>

排列... 我尝试了以下所有排列:

  • 全局声明:同时使用cdata-section和preserve-space,只使用一个或另一个
  • 源代码xml文档包含/不包含xml:space =&#34;保留&#34;,代码元素和外部元素。

总共有6种排列。

这些设置似乎对我没什么影响。以下是每个测试块的输出:

  • 阻止&#39;复制&#39;:清空(无文本输出)
  • 阻止&#39;复制文字&#39;:空(无文本输出)
  • 阻止&#39;原创&#39;:代码,但删除了所有新行
  • 阻止&#39;规范化空间&#39;:空(无文本输出)
  • 阻止&#39;使用额外的CDATA包装进行复制?&#39;:空(无文本输出)
  • 阻止&#39;再次尝试包装&#39;:代码,但删除了所有新行

3 个答案:

答案 0 :(得分:2)

(代表OP发布。此解决方案是对该问题的修改,因此我已将该编辑推回并在此处发布。)

输入XML:

<?xml version="1.0" encoding="iso-8859-1"?>
<solution>
   <solution_name>A Set of Functions</solution_name>
   <description>Just for the sake of example</description>
   <functions>
      <function>
        <code><![CDATA[function String getStringSafely(String textToCheck, String defaultValue) {
                if (textToCheck == null || textToCheck.length() <= 0) {
                    return defaultValue;
                }
                return textToCheck;
            }
        ]]></code>
      </function>
      <function><code><![CDATA[import java.nio.charset.Charset;
import com.example.library.Something;

function String doSomething(String key) {
        if (key == null || key.length() <= 0) {
            return "";
        }
        System.out.println(String.format("Yep, got a value[%1$s]", key));
    }
]]></code>
      </function>
    </functions>
</solution>

示例XSL:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns="http://www.w3.org/TR/xhtml1/strict" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    exclude-result-prefixes="fo" 
    >
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" cdata-section-elements="code"/>
<xsl:preserve-space elements="code" />
<xsl:template match="solution">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">

  <fo:layout-master-set>
    <fo:simple-page-master master-name="solution-page">
      <fo:region-body margin="1in"/>
    </fo:simple-page-master>
  </fo:layout-master-set>

  <fo:page-sequence master-reference="solution-page">
    <fo:flow flow-name="xsl-region-body" id="solution">
        <fo:block text-align="center" 
        space-after="40pt" space-before="100pt" space-after.precedence="3" 
        font-family="Helvetica" font-weight="bold" font-size="14pt" color="#0050B2" >
                <xsl:value-of select="solution_name"/>
        </fo:block>
        <fo:block font-family="Helvetica" font-size="12pt" color="black" 
    space-after="12pt" space-before="12pt" space-before.precedence="4">
            <xsl:value-of select="description"/>
        </fo:block>
        <xsl:for-each select="functions">
            <xsl:variable name="this" select="." />
            <xsl:call-template name="solution_functions">
                <xsl:with-param name="data" select="$this"/>
            </xsl:call-template>
        </xsl:for-each>
    </fo:flow>
  </fo:page-sequence>
</fo:root>
</xsl:template>

<xsl:template name="solution_functions">
    <xsl:param name="data"/>
  <fo:block id="functions" break-before="page" 
            font-family="Helvetica"
            font-weight="bold"
            font-size="14pt"
            color="#0050B2" space-after="12pt"
            space-before="16pt" space-after.precedence="3">
        Functions
  </fo:block>
    <xsl:for-each select="$data/function">
        <xsl:variable name="this" select="." />
        <xsl:call-template name="present_function">
            <xsl:with-param name="data" select="$this"/>
        </xsl:call-template>
    </xsl:for-each>
</xsl:template>

<xsl:template name="present_function">
    <xsl:param name="data"/>
    <fo:block 
                font-family="Helvetica"
                font-weight="bold"
                font-size="12pt" 
                space-after="12pt"
                space-before="16pt" space-after.precedence="3">
            Code
    </fo:block>
    <fo:block font-family="Helvetica" font-size="12pt" color="black" 
        space-after="12pt" space-before="12pt" space-before.precedence="4">
        <fo:block>
            <xsl:text>This works! Thanks ...</xsl:text>
            <fo:block linefeed-treatment="preserve" 
                      white-space-collapse="false" 
                      white-space-treatment="preserve">
                <xsl:value-of select="$data/code"/>
            </fo:block>
        </fo:block>
    <fo:block>
       [ All following examples were part of the original post. The above is the one which works. The below, kept for future reference to original question. ]
    </fo:block>
    <fo:block>
        <xsl:text>Original</xsl:text>
        <fo:block linefeed-treatment="preserve" 
                  white-space-collapse="false" 
                  white-space-treatment="preserve">
            <xsl:value-of select="$data/code"/>
        </fo:block>
    </fo:block>

      <fo:block>
          <xsl:text>Copy</xsl:text>
          <xsl:copy>
            <xsl:value-of select="$data/code"/>
          </xsl:copy>
      </fo:block>

      <fo:block>
          <xsl:text>Copy Text</xsl:text>
          <xsl:copy>
            <xsl:value-of select="$data/code/text()"/>
          </xsl:copy>
      </fo:block>

      <fo:block>
          <xsl:text>Original</xsl:text>
          <xsl:value-of select="$data/code"/>
      </fo:block>

      <fo:block>
          <xsl:text>Normalise space</xsl:text>
          <value-of select="normalize-space($data/code)" disable-output-escaping="yes"/>
      </fo:block>

      <fo:block>          
          <xsl:text>Copy with extra CDATA wrapper?</xsl:text>
          <xsl:copy>
            <xsl:text disable-output-escaping="yes"><![CDATA[<![CDATA[]]></xsl:text>
            <xsl:value-of select="$data/code"/>
            <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
          </xsl:copy>         
      </fo:block>

      <fo:block>
        <xsl:text>Again, an attempt to wrap</xsl:text>
        <xsl:text disable-output-escaping="yes">
          &lt;![CDATA[
        </xsl:text>
        <xsl:value-of select="$data/code" />
        <xsl:text disable-output-escaping="yes">
          ]]&gt;
        </xsl:text>
      </fo:block>

    </fo:block>
</xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

让我们澄清代码中反映的一些基本误解。

  1. 正如@ michael.hor257k所提到的,你没有xsl:template 结构体。对于简化的样式表,这实际上是可以的 你正在尝试,但这种形式没有xsl:stylesheet根 元件;它只是从你想要的XML根元素开始 输出XML。然后,它会在您执行时从输入XML中提取 xsl:value-of/@select构造。因此,主要修复#1是添加 <xsl:template match="/">...或删除<xsl:stylesheet>。好 使用第二个选项(简化样式表),因为它似乎是你喜欢的。
  2. 接下来,意识到你的XPath无法选择任何东西,所以 你的所有测试用例都没有证明什么。主要修复#2:而不是 选择"code/',在所有测试中选择"/myxml/code" 例。
  3. 以下是您进行上述更改(以及其他一些小修补程序)的测试用例:

    <?xml version="1.0" encoding="iso-8859-1"?>
    <fo:block font-family="Courier New" font-size="12pt" color="black" 
              space-after="12pt" space-before="12pt" space-before.precedence="4"
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              xmlns:fo="http://www.w3.org/1999/XSL/Format"
              xsl:version="1.0">
      <fo:block>
        <xsl:text>Copy</xsl:text>
        <xsl:copy>
          <xsl:value-of select="/myxml/code"/>
        </xsl:copy>
      </fo:block>
      <fo:block>
        <xsl:text>Copy Text</xsl:text>
        <xsl:copy>
          <xsl:value-of select="/myxml/code/text()"/>
        </xsl:copy>
      </fo:block>
      <fo:block>
        <xsl:text>Original</xsl:text>
        <xsl:value-of select="/myxml/code"/>
      </fo:block>
      <fo:block>
        <xsl:text>Normalise space</xsl:text>
        <xsl:value-of select="normalize-space(code)" disable-output-escaping="yes"/>
      </fo:block>
      <fo:block>          
        <xsl:text>Copy with extra CDATA wrapper?</xsl:text>
        <xsl:copy>
          <xsl:text disable-output-escaping="yes"><![CDATA[<![CDATA[]]></xsl:text>
          <xsl:value-of select="/myxml/code"/>
          <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
        </xsl:copy>         
      </fo:block>
      <fo:block>
        <xsl:text>Again, an attempt to wrap</xsl:text>
        <xsl:text disable-output-escaping="yes">
          &lt;![CDATA[
        </xsl:text>
        <xsl:value-of select="/myxml/code" />
        <xsl:text disable-output-escaping="yes">
          ]]&gt;
        </xsl:text>
      </fo:block>
    </fo:block>
    

    针对您的输入XML运行上述XSLT会产生更多有用的测试结果:

    <?xml version="1.0" encoding="UTF-8"?><fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="Courier New" font-size="12pt" color="black" space-after="12pt" space-before="12pt" space-before.precedence="4"><fo:block>Copyimport java.nio.charset.Charset;
        import com.my.library.AClass;
        import com.my.library.AnotherClass;
    
        public String getStringValue(String key) {
                // Just some ramblings
    
                // Dummy code...
                if (key != null &amp;&amp; key.length() &gt; 0) {
                    System.out.println(key);
                }
            }
        </fo:block><fo:block>Copy Textimport java.nio.charset.Charset;
        import com.my.library.AClass;
        import com.my.library.AnotherClass;
    
        public String getStringValue(String key) {
                // Just some ramblings
    
                // Dummy code...
                if (key != null &amp;&amp; key.length() &gt; 0) {
                    System.out.println(key);
                }
            }
        </fo:block><fo:block>Originalimport java.nio.charset.Charset;
        import com.my.library.AClass;
        import com.my.library.AnotherClass;
    
        public String getStringValue(String key) {
                // Just some ramblings
    
                // Dummy code...
                if (key != null &amp;&amp; key.length() &gt; 0) {
                    System.out.println(key);
                }
            }
        </fo:block><fo:block>Normalise space</fo:block><fo:block>Copy with extra CDATA wrapper?<![CDATA[import java.nio.charset.Charset;
        import com.my.library.AClass;
        import com.my.library.AnotherClass;
    
        public String getStringValue(String key) {
                // Just some ramblings
    
                // Dummy code...
                if (key != null &amp;&amp; key.length() &gt; 0) {
                    System.out.println(key);
                }
            }
        ]]></fo:block><fo:block>Again, an attempt to wrap
          <![CDATA[
        import java.nio.charset.Charset;
        import com.my.library.AClass;
        import com.my.library.AnotherClass;
    
        public String getStringValue(String key) {
                // Just some ramblings
    
                // Dummy code...
                if (key != null &amp;&amp; key.length() &gt; 0) {
                    System.out.println(key);
                }
            }
    
          ]]>
        </fo:block></fo:block>
    

    我相信您可以从中找出产生您所寻求结果的测试用例结果。

答案 2 :(得分:0)

将您的代码放在fo:block中,并设置以下属性来控制空格和回车的处理:

像这样:

<fo:block>
    <xsl:text>Original</xsl:text>
    <fo:block linefeed-treatment="preserve" 
              white-space-collapse="false" 
              white-space-treatment="preserve">
        <xsl:value-of select="code"/>
    </fo:block>
</fo:block>