Как этот XSL может быть реорганизован, чтобы использовать преимущества apply-templates? - PullRequest
3 голосов
/ 03 марта 2011

Отвечая на этот вопрос о прекрасном XSL , но уточняйте, как я должен реорганизовать этот XSL, чтобы использовать преимущества apply-templates и / или keys.

Я склонен «чрезмерно использовать» каждый элемент для управления контекстом источника, и я могу себе представить, что apply-templates могут помочь. Несмотря на большое количество Google, я все еще не понимаю, как управлять контекстом в нескольких шаблонах.

В следующем примере, как можно уменьшить количество повторяющихся сегментов XPath путем рефакторинга?

    <xsl:template match="/">
    <xsl:element name="Body">
        <xsl:element name="Person">
            <xsl:if     test="/source/dbSrc/srv/v[@name='name']/text()='false'">
                <xsl:element name="PhoneNumber" />
                <xsl:element name="Zip">
                    <xsl:value-of
                        select="/source/req[1]/personal-info/address-info/zip-code" />

                </xsl:element>
            </xsl:if>
            <xsl:if test="/source/dbSrc/srv/v[@name='name']/text()='true'">
                <xsl:element name="PhoneNumber" />
                <xsl:element name="Zip">
                    <xsl:value-of select="/source/req[3]/personal-info/address-info/zip-code" />
                </xsl:element>
            </xsl:if>
        </xsl:element>

</xsl:template>

Ответы [ 2 ]

1 голос
/ 03 марта 2011

В XSLT 2.0 я бы написал так:

<xsl:template match="/">
    <Body>
        <Person>
          <PhoneNumber/>
          <Zip>
            <xsl:variable name="index" as="xs:integer"
               select="if (/source/dbSrc/srv/v[@name='name']='true') then 3 else 1"/>
            <xsl:value-of select="/source/req[$index]/personal-info/address-info/zip-code"/>
          </Zip>
        </Person>
    </Body>
</xsl:template>

С 1.0 переменная xsl: становится немного более сложной, но в остальном она такая же.

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

Здесь очень мало времени для использования шаблонных правил, потому что вы используете очень мало входных данных, и потому что вы, кажется, точно знаете, где их найти. Шаблонные правила вступают в свои права, если вы хотите быть менее жесткими, точно зная, где именно вы ищите источник: они помогают сделать код более устойчивым к изменчивости и изменению входных данных. Но, не видя источника и не зная дополнительных сведений, мы не можем сказать вам, где нужна эта гибкость. Жесткое кодирование индексов «1» и «3» кажется мне сигналом опасности, но только вы можете судить об этом.

1 голос
/ 03 марта 2011

Один из начальных способов рефакторинга данного кода будет следующим:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:template match="/">
  <Body>
   <Person>
    <PhoneNumber/>
     <Zip>
       <xsl:apply-templates select=
        "/*/dbSrc/srv/v[@name='name']"/>
     </Zip>
   </Person>
  </Body>
 </xsl:template>

 <xsl:template match="v[@name='name' and .='true']">
   <xsl:value-of select=
   "/*/req[3]/personal-info/address-info/zip-code"/>
 </xsl:template>

 <xsl:template match="v[@name='name' and .='false']">
   <xsl:value-of select=
   "/*/req[1]/personal-info/address-info/zip-code"/>
 </xsl:template>
</xsl:stylesheet>

Примечание : рефакторированный код не содержит никаких условных xsltинструкции.

Дальнейший рефакторинг может позволить нам избавиться от последних тоже шаблонов , потому что в этом случае дополнительные шаблоны на самом деле не нужны - код создает только один элемент и зависит отединственное условие:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:variable name="vCond" select=
  "/*/dbSrc/srv/v[@name='name']/text()='true'"/>

 <xsl:variable name="vInd" select=
  "3*$vCond + 1*not($vCond)"/>

 <xsl:template match="/">
  <Body>
   <Person>
    <PhoneNumber/>
     <Zip>
      <xsl:value-of select=
      "/*/req[position()=$vInd]
                /personal-info/address-info/zip-code"/>
     </Zip>
   </Person>
  </Body>
 </xsl:template>
</xsl:stylesheet>

Примечание : Здесь мы предполагаем, что /*/dbSrc/srv/v[@name='name']/text() может иметь только два возможных значения: 'true' или 'false'

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...