использование xslt для интерпретации плоского xml во вложенный xhtml - PullRequest
1 голос
/ 23 сентября 2010

Я пытаюсь написать XSLT, который будет выбирать непосредственных братьев и сестер определенного типа, но останавливаться при достижении другого тега.

Вот исходный XML:

<?xml version="1.0"?> 
<body> 
    <proc>Test</proc> 
    <alert>Test1: alert 1</alert> 
    <alert>Test1: alert 2</p> 
    <para>Test para 1</para> 
    <alert>Test2: alert 1</alert> 
    <alert>Test2: alert 2</alert> 
    <alert>Test2: alert 3</alert> 
    <proc>Test</proc> 
    <alert>Test3: alert 1</alert> 
    <alert>Test3: alert 2</alert> 
    <alert>Test3: alert 3</alert> 
</html>

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

<?xml version="1.0" encoding="UTF-8"?> 
<body>
    <proc>
        <alert>Test1: alert 1</alert>
        <alert>Test1: alert 2</alert>
    </proc>
    <para>Test para 1</para>
    <alert>Test2: alert 1</alert>
    <alert>Test2: alert 2</alert>
    <alert>Test2: alert 3</alert>
    <proc>
        <alert>Test3: alert 1</alert>
        <alert>Test3: alert 2</alert>
        <alert>Test3: alert 3</alert>
    </proc>
</body>

это вообще возможно?

Вот мой текущий xsl, который не выполняет трюк:

<xsl:template match="proc">
    <xsl:variable name="procedure" select="."/>
    <xsl:apply-templates/>
    <xsl:for-each 
     select="following-sibling::alert[preceding-sibling::proc[1] = $procedure]">
        <xsl:apply-templates select="."/>
    </xsl:for-each>
</xsl:template>


<xsl:template match="c:hhtAlert">...</xsl:template>

<xsl:template match="c:hhtPara">...</xsl:template>

Ответы [ 3 ]

0 голосов
/ 23 сентября 2010

Вот эффективное и довольно короткое решение XSLT 1.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:key name="kFollowing" match="alert"
     use="generate-id(preceding-sibling::*
                      [
                       self::proc
                      or
                       self::para
                       ]
                        [1]
                          [self::proc]
                    )"/>

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

 <xsl:template match="proc">
  <proc>
   <xsl:apply-templates select="key('kFollowing', generate-id())" mode="copy"/>
  </proc>
 </xsl:template>

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

 <xsl:template match="alert[preceding-sibling::*
                [
                 self::proc
                or
                 self::para
                ]
                 [1]
                   [self::proc]
               ]"
                              />
</xsl:stylesheet>

, когда это преобразование применяется к предоставленному XML-документу (исправлено, чтобы быть корректным ):

<body>
    <proc>Test</proc>
    <alert>Test1: alert 1</alert>
    <alert>Test1: alert 2</alert>
    <para>Test para 1</para>
    <alert>Test2: alert 1</alert>
    <alert>Test2: alert 2</alert>
    <alert>Test2: alert 3</alert>
    <proc>Test</proc>
    <alert>Test3: alert 1</alert>
    <alert>Test3: alert 2</alert>
    <alert>Test3: alert 3</alert>
</body>

желаемый результат получен :

<body>
   <proc>
      <alert>Test1: alert 1</alert>
      <alert>Test1: alert 2</alert>
   </proc>
   <para>Test para 1</para>
   <alert>Test2: alert 1</alert>
   <alert>Test2: alert 2</alert>
   <alert>Test2: alert 3</alert>
   <proc>
      <alert>Test3: alert 1</alert>
      <alert>Test3: alert 2</alert>
      <alert>Test3: alert 3</alert>
   </proc>
</body>

Примечание : использование ключей делает это преобразованиево много раз быстрее (в случае многих братьев и сестер alert), чем при использовании осей preceding-sibling:: или following-sibling::.

0 голосов
/ 23 сентября 2010

Помимо хорошего ответа Димитра (вероятно, классического решения для такого рода проблем), эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="proc">
        <proc>
            <xsl:apply-templates select="following-sibling::node()[1]"
                                 mode="open"/>
        </proc>
        <xsl:apply-templates select="following-sibling::node()
                                         [not(self::alert)][1]"/>
    </xsl:template>
    <xsl:template match="node()" mode="open"/>
    <xsl:template match="alert" mode="open">
        <xsl:copy-of select="."/>
        <xsl:apply-templates select="following-sibling::node()[1]"
                             mode="open"/>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<body>
    <proc>
        <alert>Test1: alert 1</alert>
        <alert>Test1: alert 2</alert>
    </proc>
    <para>Test para 1</para>
    <alert>Test2: alert 1</alert>
    <alert>Test2: alert 2</alert>
    <alert>Test2: alert 3</alert>
    <proc>
        <alert>Test3: alert 1</alert>
        <alert>Test3: alert 2</alert>
        <alert>Test3: alert 3</alert>
    </proc>
</body>

Примечание :При этом используется мелкозернистый обход.

Редактировать : Лучшее сопоставление с модой.

0 голосов
/ 23 сентября 2010

Если вы используете XSLT 2, должно работать что-то вроде следующего:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="body">
    <xsl:copy>
      <xsl:for-each-group select="*" group-starting-with="para | proc">
        <xsl:choose>
          <xsl:when test="self::para">
            <xsl:apply-templates select="current-group()"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:copy>
              <xsl:apply-templates select="current-group()[position() &gt; 1]"/>
            </xsl:copy>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...