开发者

Move certain nodes that are sibling of select node into a new parent node

I did some searching here and found some questions that were related to my problem, but I'm still having trouble...(hope it's ok that I'm adding a new question instead of commenting on an existing one..)

<?xml version="1.0"?>
<section>
    <title>Main Section</title>
    <para>Here is some text that is a child of a main section.</para>
    <para>Some more text.</para>
    <para>When a section has subsections, it should not have loose paragraphs before the first sub section. Those loose paras should be placed inside a comment element.</para>
    <section>
        <title>This is my subsection</title>
        <para>Text that is inside of the sub-section</para>
        <para>And some more sub section text.</para>
    </section>
</section>

I want to have the /section/para placed inside a newly created comment node, like so:

<?xml version="1.0"?>
<section>
    <title>Main Section</title>
    <comment>
       <para>Here is some text that is a child of a main section.</para>
       <para>Some more text.</para>
       <para>When a section has subsections, it should not have loose paragraphs before the first sub section. Those loose paras should be placed inside a comment element.</para>
    </comment>
    <section>
        <title>This is my subsection</title>
        <para>Text that is inside of the sub-section</para>
        <para>And some more sub section text.</para>
    </section>
</section>

I tried some of the suggestions I found searching stackoverflow, the closest one is here.

This is the stylesheet I'm using:

<?xml version='1.0'?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
开发者_StackOverflow中文版<xsl:output method="xml"/>


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


<!-- paras that are children of a section that has direct para children and dircect section children -->
<xsl:template match="section[para][section]/para[1]">
    <comment>
        <xsl:apply-templates select="../para" mode="commentPara"/>

    </comment>
</xsl:template>

<xsl:template match="*" mode="commentPara">
    <xsl:call-template name="identity"/>
</xsl:template>

<xsl:template match="section[para][section]/para"/>


</xsl:stylesheet>

It's outputting this:

<?xml version='1.0' ?>
<section>
    <title>Main Section</title>



    <section>
        <title>This is my subsection</title>
        <para>Text that is inside of the sub-section</para>
        <para>And some more sub section text.</para>
    </section>
</section>

simply deleting the paras I want to wrap in a comment tag. I tried going essentially line by line through the stylesheet in the question I linked to...any ideas? thanks, bp


That's grouping adjacents para elements.

The problem is in Conflict Resolution for Template Rules: because both para matching rules have the same import precedence and the same calculated priority, error recovery mechanism could lead to apply last one.

You need to explicitly define a @priority on the "first para child" rule like:

<xsl:template match="section[para][section]/para[1]" priority="1">
</

With such modification, the output is:

<?xml version="1.0" encoding="UTF-16"?>
<section>
    <title>Main Section</title>
    <comment>
        <para>Here is some text that is a child of a main section.</para>
        <para>Some more text.</para>
        <para>When a section has subsections, it should not have loose paragraphs before the first sub section. Those loose paras should be placed inside a comment element.</para>
    </comment>
    <section>
        <title>This is my subsection</title>
        <para>Text that is inside of the sub-section</para>
        <para>And some more sub section text.</para>
    </section>
</section>


I would do it this way:

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

 <xsl:key name="kPreceding" match="para"
  use="generate-id(following-sibling::section[1])"/>

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

 <xsl:template match="section[preceding-sibling::para]">
  <comment>
   <xsl:apply-templates mode="copy"
        select="key('kPreceding', generate-id())"/>
  </comment>

  <xsl:call-template name="identity"/>
 </xsl:template>

 <xsl:template match=
  "para[following-sibling::section]"/>

 <xsl:template match="para" mode="copy">
  <xsl:call-template name="identity"/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the provided XML document:

<section>
    <title>Main Section</title>
    <para>Here is some text that is a child of a main section.</para>
    <para>Some more text.</para>
    <para>When a section has subsections, it should not have loose paragraphs before the first sub section. Those loose paras should be placed inside a comment element.</para>
    <section>
        <title>This is my subsection</title>
        <para>Text that is inside of the sub-section</para>
        <para>And some more sub section text.</para>
    </section>
</section>

the wanted, correct result is produced:

<section>
   <title>Main Section</title>
   <comment>
      <para>Here is some text that is a child of a main section.</para>
      <para>Some more text.</para>
      <para>When a section has subsections, it should not have loose paragraphs before the first sub section. Those loose paras should be placed inside a comment element.</para>
   </comment>
   <section>
      <title>This is my subsection</title>
      <para>Text that is inside of the sub-section</para>
      <para>And some more sub section text.</para>
   </section>
</section>

Explanation:

  1. The identity rule (template) copies every node "as-is".

  2. The overriding template for section that has preceding sibling(s) para wraps all such siblings with a comment element, then calls the identity transformation on itself.

  3. For convenience we define a key that matches all para elements preceding a section element with a given generate-id().

  4. The para elements that have a following sibling section are excluded from the action of the identity rule by an overriding template, that simply does nothing.

  5. Finally, such para elements, when being output within the wrapper comment are processed in mode copy, which simply calls the identity rule to do the copying.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜