XSLT разбивает дерево на дочернем узле - PullRequest
5 голосов
/ 26 февраля 2011

Я пытаюсь разбить дерево элементов на основе расположения потомка элемента. (В частности, я пытаюсь проанализировать IDML от Adobe.) Я хотел бы иметь возможность преобразовать дерево, которое выглядит следующим образом:

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bar">
  <Content>foo</Content>
  <Br />
  <Content>bar</Content>
 </CharacterStyleRange>
 <CharacterStyleRange style="bop">
  <Content>baz</Content>
  <Br />
  <Hyperlink>
   <Content>boo</Content>
    <Br />
   <Content>meep</Content>
  </Hyperlink>
</ParagraphStyleRange>

на расщепленные деревья:

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bar">
  <Content>foo</Content>
 </CharacterStyleRange>
</ParagraphStyleRange>

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bar">
  <Content>bar</Content>
 </CharacterStyleRange>
 <CharacterStyleRange style="bop">
  <Content>baz</Content>
 </CharacterStyleRange>
</ParagraphStyleRange>

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bop">
  <Hyperlink>
   <Content>boo</Content>
  </Hyperlink>
 </CharacterStyleRange>
</ParagraphStyleRange>

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bop">
  <Hyperlink>
   <Content>meep</Content>
  </Hyperlink>
 </CharacterStyleRange>
</ParagraphStyleRange>

, который я могу затем проанализировать, используя обычный XSL. (РЕДАКТИРОВАТЬ: я изначально показывал теги <Br/> в их первоначальном месте, но на самом деле не имеет значения, есть они там или нет, так как информация, которую они содержали, теперь представлена ​​разделенными элементами. Я думаю, что, вероятно, легче решить эта проблема, не беспокоясь о том, чтобы держать их.)

Я пытался использовать xsl:for-each-group, как предложено в спецификации XSLT 2.0 (например, <xsl:for-each-group select="CharacterStyleRange/*" group-ending-with="Br">), но я не могу понять, как применить это на каждом уровне дерева (теги <Br /> могут появляться на любом уровне Например, внутри элемента <Hyperlink> внутри элемента <CharacterStyleRange>, и это также ограничивает меня только наличием шаблонов, которые применяются на выбранной глубине.

РЕДАКТИРОВАТЬ: мой пример кода показывает только одно место, где дерево должно быть разделено, но может быть любое количество точек разделения (хотя всегда один и тот же элемент.)

РЕДАКТИРОВАТЬ 2: Я добавил более подробный пример, чтобы показать некоторые из сложностей.

1 Ответ

6 голосов
/ 27 февраля 2011

Это преобразование XSLT 1.0 (и, конечно, также XSLT 2.0):

<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:template match="text()"/>

       <xsl:template match="/">
         <xsl:call-template name="Split">
          <xsl:with-param name="pSplitters"
           select="//Br"/>
         </xsl:call-template>
       </xsl:template>

       <xsl:template name="Split">
         <xsl:param name="pSplitters"/>

         <xsl:if test="$pSplitters">
           <xsl:for-each select="$pSplitters[1]">

             <xsl:call-template name="buildTree">
              <xsl:with-param name="pLeafs" select=
              "preceding-sibling::node()[not(descendant::Br)]"/>
          </xsl:call-template>

          <xsl:if test=
            "not(following-sibling::node()//Br)">
                 <xsl:call-template name="buildTree">
                  <xsl:with-param name="pLeafs" select=
                  "following-sibling::node()"/>
                 </xsl:call-template>
          </xsl:if>

          <xsl:call-template name="Split">
            <xsl:with-param name="pSplitters" select=
             "$pSplitters[position() > 1]"/>
          </xsl:call-template>
          </xsl:for-each>
         </xsl:if>
       </xsl:template>

 <xsl:template name="buildTree">
  <xsl:param name="pAncestors" select="ancestor::*"/>
  <xsl:param name="pLeafs"/>

  <xsl:choose>
    <xsl:when test="not($pAncestors)">
     <xsl:copy-of select="$pLeafs"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="vtopAncestor" select="$pAncestors[1]"/>

      <xsl:element name="{name($vtopAncestor)}"
           namespace="{namespace-uri($vtopAncestor)}">
        <xsl:copy-of select=
             "$vtopAncestor/namespace::* | $vtopAncestor/@*"/>
        <xsl:call-template name="buildTree">
          <xsl:with-param name="pAncestors"
               select="$pAncestors[position()>1]"/>
          <xsl:with-param name="pLeafs" select="$pLeafs"/>
        </xsl:call-template>
      </xsl:element>
     </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

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

<ParagraphStyleRange style="foo">
    <CharacterStyleRange style="bar">
        <Content>foo</Content>
        <Br />
        <Content>bar</Content>
    </CharacterStyleRange>
    <CharacterStyleRange style="bop">
        <Content>baz</Content>
        <Br />
        <Hyperlink>
            <Content>boo</Content>
            <Br />
            <Content>meep</Content>
        </Hyperlink>
    </CharacterStyleRange>
</ParagraphStyleRange>

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

<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bar">
      <Content>foo</Content>
   </CharacterStyleRange>
</ParagraphStyleRange>
<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bar">
      <Content>bar</Content>
   </CharacterStyleRange>
</ParagraphStyleRange>
<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bop">
      <Content>baz</Content>
   </CharacterStyleRange>
</ParagraphStyleRange>
<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bop">
      <Hyperlink>
         <Content>boo</Content>
      </Hyperlink>
   </CharacterStyleRange>
</ParagraphStyleRange>
<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bop">
      <Hyperlink>
         <Content>meep</Content>
      </Hyperlink>
   </CharacterStyleRange>
</ParagraphStyleRange>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...