【问题标题】:Selecting multiple text() nodes between elements在元素之间选择多个 text() 节点
【发布时间】:2014-02-19 14:53:51
【问题描述】:

我需要将以下 xml 完全按照如下所示输出到浏览器:

<?xml version="1.0" encoding="UTF-8"?>
<content>
  <text>
    <h1>Services</h1>
    <h2>Engineering</h2>
    This is the first bit of text:
      <listofitems>
        <listitem>Database Analysis Tools</listitem>
        <listitem>Website Development</listitem>
        <listitem>Intranet Development</listitem>
        <listitem>Database Development</listitem>
      </listofitems> 
    This is the second piece of text:
      <listofitems>
        <listitem>Hardware</listitem>
        <listitem>Software</listitem>
      </listofitems>
    This is the final piece of text.
  </text>
</content>

问题在于 元素内的文本字符串 - 未包含在它们自己的标签中的位,即“这是文本的第一位:”、“这是第二段文本:”和“这是最后一段文字。'

如果我使用 ,我可以在一个块中输出所有三个文本位,但显然它们在原始 XML 中不是这样显示的。如果我使用 我什么也得不到(我相信 text() 只引用第一个子节点,在这种情况下是另一个元素)。

我可以用 输出最后一段文本;我可以通过直接引用来访问每个 text() 节点,例如,但由于这是用于随机 XML 的,它可以是任何格式,我将无法以这种方式直接引用节点。我在 text()[*] 上尝试了 for-each,但它没有用。有什么想法可以做到这一点吗?

【问题讨论】:

    标签: xml xslt xpath xslt-1.0


    【解决方案1】:

    如果文本节点是text 元素的子节点,则编写一个单独的模板来匹配文本节点:

    <xsl:template match="text()[parent::text]">
    

    这样,中间的任何其他子元素都不会干扰。然后,编写第二个模板以防止您的 XSLT 处理器也在 listitem 元素内输出文本:

    <xsl:template match="*[parent::text]"/>
    

    如果您省略了上面的模板匹配,XSLT 的默认行为将导致作为listitem 子级的任何文本节点也被输出。

    请注意,XSLT 1.0 和 2.0 对文本节点的处理方式不同。您的一种方法:

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

    实际上输出 XSLT 2.0 中的所有文本节点。下面是一个适用于 1.0 和 2.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"/>
       <xsl:strip-space elements="*"/>
    
       <xsl:template match="//text">
          <xsl:apply-templates/>
       </xsl:template>
    
       <xsl:template match="text()[parent::text]">
          <xsl:value-of select="."/>
       </xsl:template>
    
       <xsl:template match="*[parent::text]"/>
    
    </xsl:stylesheet>
    

    输出

    This is the first bit of text: This is the second piece of text: This is the final piece of text.
    

    或者,如果您不需要处理text 的子元素,则将select 属性添加到apply-templates

    <?xml version="1.0" encoding="utf-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
       <xsl:template match="//text">
          <xsl:apply-templates select="text()"/>
       </xsl:template>
    
       <xsl:template match="text()[parent::text]">
          <xsl:copy/>
       </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

      【解决方案2】:

      当这个样式表:

      <?xml version="1.0" encoding="UTF-8"?>
      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          version="1.0">
          <xsl:strip-space elements="*"/>
      
          <xsl:template match="@*|node()">
              <xsl:copy>
                  <xsl:apply-templates select="@*|node()"/>
              </xsl:copy>
          </xsl:template>
      
          <xsl:template match="content/text/text()">
              <span><xsl:value-of select="."/></span>
          </xsl:template>
      
      </xsl:stylesheet>
      

      应用于您的输入。它输出:

      <?xml version="1.0" encoding="utf-8"?>
      <content>
          <text>
              <h1>Services</h1>
              <h2>Engineering</h2>
              <span>This is the first bit of text:</span>
              <listofitems>
                  <listitem>Database Analysis Tools</listitem>
                  <listitem>Website Development</listitem>
                  <listitem>Intranet Development</listitem>
                  <listitem>Database Development</listitem>
              </listofitems>
              <span>This is the second piece of text:</span>
              <listofitems>
                  <listitem>Hardware</listitem>
                  <listitem>Software</listitem>
              </listofitems>
              <span>This is the final piece of text.</span>
          </text>
      </content>
      

      这会解决您的问题吗?

      【讨论】:

      • 它很有用,但我不能直接按名称引用任何元素,因为这将用于一般地显示 XML。我使用的 XML 只是可能必须显示的示例。
      • @stuffedbadger :您有责任准确显示您需要什么样的输出以及您的 实际 输入 XML 的样子。请更清楚地说明这一点。否则人们下次可能不愿意花时间在答案上。
      • 我不知道我能比“完全按照下面显示的方式将以下 xml 输出到浏览器”和“因为这意味着与随机 XML 一起使用”任何格式我都无法直接引用节点”。如果这令人困惑,我深表歉意。
      【解决方案3】:

      经过一番折腾,我认为这已经足够接近可以接受了:

      <?xml version="1.0" encoding="utf-8"?>
      
      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      
      <xsl:template match="*">
        <xsl:param name="indent"/>
          <xsl:if test="parent::* or preceding-sibling::*">
              <br/>
          </xsl:if>
            <xsl:value-of select="$indent" disable-output-escaping="yes"/>
            <!-- open angle brackets -->
            &lt;<xsl:value-of select="name()"/>
            <!-- output any attributes and values -->
            <xsl:for-each select="@*">
              <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>
              <xsl:value-of select="name(.)"/>="<b><xsl:value-of select="."/></b>"
            </xsl:for-each>
            <!-- close angle brackets -->
            &gt;
            <!-- output text content -->
            <xsl:apply-templates>
              <xsl:with-param name="indent"><xsl:value-of select="$indent"/>&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;</xsl:with-param>
            </xsl:apply-templates>
            <!-- close tag -->
            <xsl:if test="child::*">
              <br/><xsl:value-of select="$indent" disable-output-escaping="yes"/>
            </xsl:if>
            &lt;/<xsl:value-of select="name()"/>&gt;  
      </xsl:template>
      
      <xsl:template match="text()">
          <xsl:value-of select="."/>
      </xsl:template>
      
      </xsl:stylesheet>
      

      这给出了这个:

      <content> 
           <text> 
               <h1>Services</h1> 
               <h2>Engineering</h2> This is the first bit of text: 
               <listofitems> 
                   <listitem>Database Analysis Tools</listitem> 
                   <listitem>Website Development</listitem> 
                   <listitem>Intranet Development</listitem> 
                   <listitem>Database Development</listitem> 
              </listofitems> This is the second piece of text: 
               <listofitems> 
                   <listitem>Hardware</listitem> 
                   <listitem>Software</listitem> 
              </listofitems> This is the final piece of text. 
          </text> 
      </content>
      

      那些烦人的文本至少在大致正确的区域中,并且模板应该可以与任何扔给它的旧 XML 一起使用。

      非常感谢您的帮助。

      【讨论】:

        猜你喜欢
        • 2017-01-23
        • 2022-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-11
        • 2019-05-21
        • 1970-01-01
        • 2023-02-21
        相关资源
        最近更新 更多