根据其子元素将元素拆分为两个或多个元素 [英] split an element into two or more elements depending on its children

查看:28
本文介绍了根据其子元素将元素拆分为两个或多个元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于那些将来遇到这个问题的人来说,这是一个写得很糟糕的问题.这不是我所追求的.这个问题也可能对您有用.em>

所以,过去几天我一直在努力复习我的XSLT.我对它非常陌生,过去大部分时间都在使用 XQuery 来转换我的 XML.我被困在一个相当简单的问题上,但环顾四周,我没有找到明确的解决方案.简单地说,我想根据它的子元素将一些元素分成两个.

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

<p>培根 ipsum dolor 坐 amet 培根夹头熏牛肉猪猪臀肉、肩牛肋骨、三尖舌头.三尖地面圆形短排骨 capicola 肉饼柄鼓槌短腰熏牛肉 t-骨.牛腩 turducken 短排骨 T 骨 andouille 条牛排猪腰咸牛肉汉堡培根菲力牛排猪排尾.<note.ref id="0001"><super>1</super></note.ref><note id="0001"><p>您可能需要咨询拉丁屠夫.祝你好运.</p></注意>猪里脊肉肋眼培根熏牛肉鸡腿牛腩,肩猪下巴.意大利腊肠牛腩臀部火腿,尾巴汉堡条牛排猪火腿飞节短肋骨干牛肉排骨.Capicola 短肋猪牛肉丸下巴五花肉.Doner leberkas 排骨,侧翼夹头培根培根火腿飞节猪肉汉堡包肥肉.</p></root>

在我运行我的 xsl 之后,我得到了如下内容:

<身体><p>培根 ipsum dolor 坐 amet 培根夹头熏牛肉猪猪臀肉、肩牛肋骨、三尖舌头.三尖地面圆形短排骨 capicola 肉饼柄鼓槌短腰熏牛肉 t-骨.牛腩 turducken 短排骨 T 骨 andouille 条牛排猪腰咸牛肉汉堡培根菲力牛排猪排尾.<span class="noteRef" id="0001"><sup>1</sup></span><div id="note-0001"><p>您可能需要咨询拉丁屠夫.祝你好运.</p>

猪里脊肉肋眼培根熏牛肉鸡腿牛腩,肩猪下巴.意大利腊肠牛腩臀部火腿,尾巴汉堡条牛排猪火腿飞节短肋骨干牛肉排骨.Capicola 短肋猪牛肉丸下巴五花肉.Doner leberkas 排骨,侧翼夹头培根培根火腿飞节猪肉汉堡包肥肉.</p></html>

这个问题显然是 HTML

不能有

作为一个孩子,让一个人另一个

作为孙子.这只是无效的.浏览器(例如chromium)可能会在遇到<div> 时呈现第一段结尾,适当地将注释包裹在自己的<p> 中,但是在注释孤儿之后留下文本.因此,任何应用于

的 CSS 都将无法应用.

如何根据元素后代将一个

元素拆分为两个?

期望输出

 <身体><p>培根 ipsum dolor 坐 amet 培根夹头熏牛肉猪猪臀肉、肩牛肋骨、三尖舌头.三尖地面圆形短排骨 capicola 肉饼柄鼓槌短腰熏牛肉 t-骨.牛腩 turducken 短排骨 T 骨 andouille 条牛排猪腰咸牛肉汉堡培根菲力牛排猪排尾.<span class="noteRef" id="0001"><sup>1</sup></span><</p><div id="note-0001"><p>您可能需要咨询拉丁屠夫.祝你好运.</p>

<p>猪里脊肉肋眼培根熏牛肉鸡腿牛腩,肩猪下巴.意大利腊肠牛腩臀部火腿,尾巴汉堡条牛排猪火腿飞节短肋骨干牛肉排骨.Capicola 短肋猪牛肉丸下巴五花肉.Doner leberkas 排骨,侧翼夹头培根培根火腿飞节猪肉汉堡包肥肉.</p></html>

我已经稍微抽象了我的问题,因此我尝试过的以下 XSL 可能会稍微偏离.

<xsl:template match="/"><身体><xsl:apply-templates/></html></xsl:模板><xsl:template match="p"><p><xsl:apply-templates/></p></xsl:模板<xsl:template match="note.ref"><span class="noteRef" id="{@id}"><xsl:apply-templates/></span></xsl:模板><xsl:template match="super"><sup><xsl:apply-templates/></sup></xsl:模板><xsl:template match="note"><div id="note-{@id}"><xsl:apply-templates/>

</xsl:模板></xsl:stylesheet>

解决方案

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

<xsl:output method="html" indent="yes" version="5.0"/><xsl:template match="/"><身体><xsl:apply-templates/></html></xsl:模板><xsl:template match="p[not((.//p, .//div))]"><xsl:copy><xsl:apply-templates select="@* , node()"/></xsl:copy></xsl:模板><xsl:template match="p[.//p, .//div]"><xsl:for-each-group select="node()" group-adjacent="boolean((self::text(), self::note.ref))"><xsl:when test="current-grouping-key()"><p><xsl:apply-templates select="current()/@*, current-group()"/></p></xsl:when><xsl:否则><xsl:apply-templates select="current-group()"/></xsl:否则></xsl:选择></xsl:for-each-group></xsl:模板><xsl:template match="note.ref"><span class="noteRef" id="{@id}"><xsl:apply-templates/></span></xsl:模板><xsl:template match="super"><sup><xsl:apply-templates/></sup></xsl:模板><xsl:template match="note"><div id="note-{@id}"><xsl:apply-templates/>

</xsl:模板></xsl:stylesheet>

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

EDIT: for those that come to this in the future, this was a poorly written question. It was not what I was after. This Question may also be of use to you.

So, I have been trying to brush up on my XSLT the past few days. I am very unfamiliar with it, spending most of my past using XQuery to transform my XML. I am stuck on a rather simple problem, but looking around I have not found a clear solution. Simply, I want to split some elements into two depending on its children.

For example, if my XML looks like the following:

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

after I run my xsl I am left with something like the following:

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

The problem with this is obviously an HTML <p> cannot have a <div> as a child, let a lone another <p> as a grandchild. This is just invalid. A browser, such as chromium, may render the first paragraph ending when it hits the <div>, wrapping, appropriately, the note in its own <p>, but leaving the text after the note orpahened. So that any CSS applied to the <p> will fail to be applied.

How would I split one <p> element into two depending on the elements descendants?

Desired output

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

I have abstracted my question slightly, so the following XSL of what I have tried could be slightly off.

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

解决方案

Assuming an XSLT 2.0 processor I think using for-each-group can help:

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

The patterns p[not((.//p, .//div))] and p[.//p, .//div] and the group-adjacent expression boolean((self::text(), self::note.ref)) might need to be extended to cover other types of nodes you expect in the input and that need the same processing.

这篇关于根据其子元素将元素拆分为两个或多个元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆