xsl - группировка узлов на основе атрибутов между 2 узлами - PullRequest
4 голосов
/ 10 апреля 2011

В XSL 1.0 я провел поиск и обнаружил похожие элементы вокруг группировки, но я думаю, что это немного отличается. Извинения, если это уже было покрыто, я не смог найти ответ

Вход

<?xml version="1.0"?>
<xmldoc>
<section paragraphMarker="true">Part 1. </section>
<section paragraphMarker="false">Part 2. </section>
<section paragraphMarker="false">Part 3. </section>
<section paragraphMarker="true">Part 4. </section>
<section paragraphMarker="true">Part 5. </section>
<section paragraphMarker="false">Part 6. </section>
</xmldoc>

Желаемый вывод

<p>Part 1. Part 2. Part 3.</p>
<p>Part 4. </p>
<p>Part 5. Part 6. </p>

Я пробовал следующее: -

<xsl:key name="sectionsWithParagraphMarker" 
    match="section[@paragraphMarker='true']" use="."/>

<xsl:template match="/">
<xsl:for-each select=
    "/xmldoc/section[generate-id()
         = 
    generate-id(key('sectionsWithParagraphMarker',.)[1])]">
   <p>
<xsl:apply-templates select="."/>
<xsl:apply-templates select="./following-sibling::node()
         [count(. | /xmldoc/section[@paragraphMarker='true'][1]/
             preceding-sibling::node())
         =
         count(/xmldoc/section[@paragraphMarker='true'][1]/
             preceding-sibling::node())
         ]"/>  
        </p>
    </xsl:for-each>
</xsl:template>

<xsl:template match="section">
    <xsl:select value-of="."/>
</xsl:template>

Это не работает, и я застрял с ним.Он выбирает слишком много узлов 'section' для всех групп.Любая помощь будет принята с благодарностью!

Ответы [ 3 ]

4 голосов
/ 10 апреля 2011
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="section">
        <xsl:if test="@paragraphMarker='true'">
            <p>
                <xsl:apply-templates select="." mode="text" />
            </p>
        </xsl:if>
    </xsl:template>

    <xsl:template match="section" mode="text">
        <xsl:value-of select="." />
        <xsl:apply-templates select="following-sibling::section[1][@paragraphMarker='false']" mode="text" />
    </xsl:template>
</xsl:stylesheet>

Поскольку этот код только смотрит вперед, он гораздо более эффективен, чем решение, выполняющее возврат в обратном направлении (оси XPath, которые идут назад, медленны во многих реализациях).

2 голосов
/ 10 апреля 2011

Это преобразование :

<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="kSectsByPara"
  match="section[not(@paragraphMarker='true')]"
  use="generate-id(preceding-sibling::*
                    [@paragraphMarker='true']
                    [1]
                   )"
 />

 <xsl:template match="*[@paragraphMarker='true']">
  <p>
   <xsl:copy-of select=
    "text()|key('kSectsByPara', generate-id())/text()"/>
  </p>
 </xsl:template>

 <xsl:template match="*/*[not(@paragraphMarker='true')]"/>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<xmldoc>
    <section paragraphMarker="true">Part 1. </section>
    <section paragraphMarker="false">Part 2. </section>
    <section paragraphMarker="false">Part 3. </section>
    <section paragraphMarker="true">Part 4. </section>
    <section paragraphMarker="true">Part 5. </section>
    <section paragraphMarker="false">Part 6. </section>
</xmldoc>

дает желаемый, правильный результат :

<p>Part 1. Part 2. Part 3. </p>
<p>Part 4. </p>
<p>Part 5. Part 6. </p>

Объяснение

<xsl:key> с именем kSectsByPara определяет отображение между generate-id() section, имеющим атрибут paragraphMarker="true", и группой следующих section элементов, имеющих свой атрибут paragraphMarker="false".

1 голос
/ 10 апреля 2011

Следующая таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="section[@paragraphMarker='true']">
        <p>
            <xsl:apply-templates
               select=".|following-sibling::section[not(@paragraphMarker='true')]
           [preceding-sibling::section[@paragraphMarker='true'][1]=current()]" 
               mode="inner"/>
        </p>
    </xsl:template>
    <xsl:template match="section" />
</xsl:stylesheet>

Создает желаемый результат:

<p>Part 1. Part 2. Part 3. </p>
<p>Part 4. </p>
<p>Part 5. Part 6. </p>

На английском языке мы выбираем всех следующих братьев и сестер, которые не являются маркером абзаца, и чей первый предшествующий брат, который равен маркер абзаца, является текущим маркером. Обратите внимание, что для этого требуется, чтобы мы перебрали всех следующих братьев и сестер и затем вернулись назад, чтобы найти предыдущий маркер (в каждом случае).

...