根据子元素将元素拆分为两个或多个元素

时间:2012-12-11 15:59:13

标签: xml xslt xslt-2.0

编辑:对于那些将来会遇到这种情况的人来说,这是一个写得不好的问题。这不是我追求的。 This Question也可能对您有用。

所以,过去几天我一直试图在我的XSLT上努力。我对它非常不熟悉,过去大部分时间都使用XQuery来转换我的XML。我陷入了一个相当简单的问题,但环顾四周我还没有找到一个明确的解决方案。简单地说,我想根据孩子的不同将一些元素分成两部分。

例如,如果我的XML如下所示:

<?xml version="1.0" encoding="UTF-8"?>    
<root>
      <p>
         Bacon ipsum dolor sit amet bacon chuck pastrami swine pork rump, shoulder beef ribs doner tri-tip 
         tongue. Tri-tip ground round short ribs capicola meatloaf shank drumstick short loin pastrami t-
         bone. Sirloin turducken short ribs t-bone andouille strip steak pork loin corned beef hamburger 
         bacon filet mignon pork chop tail.
         <note.ref id="0001"><super>1</super></note.ref>
         <note id="0001">
           <p>
             You may need to consult a latin butcher. Good Luck.
           </p>
         </note>   
       Pork loin ribeye bacon pastrami drumstick sirloin, shoulder pig jowl. Salami brisket rump ham, tail
      hamburger strip steak pig ham hock short ribs jerky shank beef spare ribs. Capicola short ribs swine   
      beef meatball jowl pork belly. Doner leberkas short ribs, flank chuck pancetta bresaola bacon ham 
      hock pork hamburger fatback.
    </p>
    </root>

在我运行xsl后,我留下了以下内容:

<html>
<body>
   <p>
         Bacon ipsum dolor sit amet bacon chuck pastrami swine pork rump, shoulder beef ribs doner tri-tip 
         tongue. Tri-tip ground round short ribs capicola meatloaf shank drumstick short loin pastrami t-
         bone. Sirloin turducken short ribs t-bone andouille strip steak pork loin corned beef hamburger 
         bacon filet mignon pork chop tail.
         <span class="noteRef" id="0001"><sup>1</sup></span>
         <div id="note-0001"> 
           <p>
               You may need to consult a latin butcher. Good Luck.
           </p>
         </div>
           Pork loin ribeye bacon pastrami drumstick sirloin, shoulder pig jowl. Salami brisket rump ham, tail
           hamburger strip steak pig ham hock short ribs jerky shank beef spare ribs. Capicola short ribs swine   
           beef meatball jowl pork belly. Doner leberkas short ribs, flank chuck pancetta bresaola bacon ham 
           hock pork hamburger fatback.
   </p>
</body>
</html>

问题显然是HTML <p>作为一个孩子不能拥有<div>,让另一个<p>作为孙子。这只是无效的。浏览器(例如chrome)可以使第一个段落在到达<div>时结束,在适当的情况下包装自己的<p>中的注释,但将注释保留在注释之后。因此,应用于<p>的任何CSS都将无法应用。

如何根据元素后代将一个<p>元素拆分为两个?

所需的输出

  <html>
    <body>
       <p>
             Bacon ipsum dolor sit amet bacon chuck pastrami swine pork rump, shoulder beef ribs doner tri-tip 
             tongue. Tri-tip ground round short ribs capicola meatloaf shank drumstick short loin pastrami t-
             bone. Sirloin turducken short ribs t-bone andouille strip steak pork loin corned beef hamburger 
             bacon filet mignon pork chop tail.
             <span class="noteRef" id="0001"><sup>1</sup></span><
</p>
             <div id="note-0001"> 
               <p>
                   You may need to consult a latin butcher. Good Luck.
               </p>
             </div>
<p>
               Pork loin ribeye bacon pastrami drumstick sirloin, shoulder pig jowl. Salami brisket rump ham, tail
               hamburger strip steak pig ham hock short ribs jerky shank beef spare ribs. Capicola short ribs swine   
               beef meatball jowl pork belly. Doner leberkas short ribs, flank chuck pancetta bresaola bacon ham 
               hock pork hamburger fatback.
       </p>
    </body>
    </html>

我略微抽象了我的问题,所以我尝试的以下XSL可能会稍微偏离。

<?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" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
    exclude-result-prefixes="xs xd" version="2.0">


<xsl:template match="/">

        <html>
          <body>
             <xsl:apply-templates/>
          </body>
        </html>
</xsl:template>

    <xsl:template match="p">
        <p>
            <xsl:apply-templates/>
        </p>
    </xsl:template


    <xsl:template match="note.ref">
        <span class="noteRef" id="{@id}">
            <xsl:apply-templates/>
        </span>
    </xsl:template>

    <xsl:template match="super">
        <sup>
            <xsl:apply-templates/>
        </sup>
    </xsl:template>

    <xsl:template match="note">
          <div id="note-{@id}">
            <xsl:apply-templates/>
        </div>
    </xsl:template>

</xsl:stylesheet>

2 个答案:

答案 0 :(得分:1)

这可能过于简化了,但您可以尝试匹配包含text()的{​​{1}}中的p并将其包裹起来(以及note之后的note.ref {1}})...

XML输入

text()

XSLT 2.0 (也可以作为1.0)

<root>
    <p>
        Bacon ipsum dolor sit amet bacon chuck pastrami swine pork rump, shoulder beef ribs doner tri-tip 
        tongue. Tri-tip ground round short ribs capicola meatloaf shank drumstick short loin pastrami t-
        bone. Sirloin turducken short ribs t-bone andouille strip steak pork loin corned beef hamburger 
        bacon filet mignon pork chop tail.
        <note.ref id="0001"><super>1</super></note.ref>
        <note id="0001">
            <p>
                You may need to consult a latin butcher. Good Luck.
            </p>
        </note>   
        Pork loin ribeye bacon pastrami drumstick sirloin, shoulder pig jowl. Salami brisket rump ham, tail
        hamburger strip steak pig ham hock short ribs jerky shank beef spare ribs. Capicola short ribs swine   
        beef meatball jowl pork belly. Doner leberkas short ribs, flank chuck pancetta bresaola bacon ham 
        hock pork hamburger fatback.
    </p>
</root>

<强>输出

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|*|processing-instruction()|comment()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/root">        
        <html>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="p[note]">
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="p[note]/text()">
        <p>
            <xsl:value-of select="normalize-space(.)"/>
            <xsl:apply-templates select="following-sibling::note.ref" mode="keep"/>
        </p>
    </xsl:template> 

    <xsl:template match="note">
        <div id="note-{@id}">
            <xsl:apply-templates/>
        </div>
    </xsl:template>

    <xsl:template match="note.ref"/>
    <xsl:template match="note.ref" mode="keep">
        <span class="noteRef" id="{@id}">
            <xsl:apply-templates/>
        </span>
    </xsl:template>

    <xsl:template match="super">
        <sup>
            <xsl:apply-templates/>
        </sup>
    </xsl:template>

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

</xsl:stylesheet>

答案 1 :(得分:1)

假设使用for-each-group的XSLT 2.0处理器可以提供帮助:

<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:output method="html" indent="yes" version="5.0"/>

<xsl:template match="/">
  <html>
    <body>
      <xsl:apply-templates/>
    </body>
  </html>
</xsl:template>

<xsl:template match="p[not((.//p, .//div))]">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="p[.//p, .//div]">
  <xsl:for-each-group select="node()" group-adjacent="boolean((self::text(), self::note.ref))">
    <xsl:choose>
      <xsl:when test="current-grouping-key()">
        <p>
          <xsl:apply-templates select="current()/@*, current-group()"/>
        </p>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="current-group()"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:template>

<xsl:template match="note.ref">
    <span class="noteRef" id="{@id}">
        <xsl:apply-templates/>
    </span>
</xsl:template>

<xsl:template match="super">
    <sup>
        <xsl:apply-templates/>
    </sup>
</xsl:template>

<xsl:template match="note">
      <div id="note-{@id}">
        <xsl:apply-templates/>
    </div>
</xsl:template>

</xsl:stylesheet>

模式p[not((.//p, .//div))]p[.//p, .//div]以及group-adjacent表达式boolean((self::text(), self::note.ref))可能需要扩展,以涵盖您在输入中期望的其他类型的节点,并且需要相同的节点处理