簡體   English   中英

調用帶有標記化參數和父上下文的XSLT模板

[英]Call XSLT template with tokenized parameter and parent context

是否可以設置對XSLT模板的調用,以使其與當前上下文的父級一起調用?

我的XML如下所示,其中Job節點具有1個以上的子位置節點:

<Job>
  <JobId>12345</JobId>
  <JobTitle>Programmer</JobTitle>
    <Location>
      <LocationCode>US</LocationCode>
      <!-- there is a variable number of comma-deliminated strings within the sublocations node -->
      <SubLocations>US1,US2,US3</SubLocations>
    </Location>
    <Location>
      <LocationCode>CAN</LocationCode>
    </Location>
</Job>

我希望輸出是每個位置或子位置的每個作業的一行:

<Id>12345</Id><Title>Programmer</Title><Location>US1</Location>
<Id>12345</Id><Title>Programmer</Title><Location>US2</Location>
<Id>12345</Id><Title>Programmer</Title><Location>US3</Location>
<Id>12345</Id><Title>Programmer</Title><Location>CAN</Location>

我的XSLT的核心邏輯如下所示:

<xsl:template match="Job/Location">
  <xsl:choose>
<!-- Test for presence of sublocation -->
    <xsl:when test="SubLocation != null">
      <xsl:for-each select="distinct-values(SubLocation/tokenize(.,','))">
        <xsl:call-template name="JobRecord">
          <xsl:with-param name="Location">
            <xsl:value-of select="."/>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:for-each>
    </xsl:when>
    <xsl:otherwise>
<!-- No Sublocation present -->
      <xsl:call-template name="JobRecord">
        <xsl:with-param name="Location">
          <xsl:value-of select="/LocationCode"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="JobRecord">
  <xsl:param name="Location"/>
  <Id><xsl:value-of select="../JobId"/></Id>
  <Name><xsl:value-of select="../JobTitle"/></Name>
  <Location><xsl:value-of select="$Location"/></Location>
</xsl:template>

即使輸出內容在Job節點級別,也需要按位置或子位置(如果適用)調用JobRecord模板。 如何在不丟失父級上下文的情況下分解或迭代子位置?

一種解決方法是將所有Job級別信息作為參數傳遞,但是我正在尋找一種更自然的XSLT方法。

您可以通過將值存儲在變量中來做到這一點,如下所示:

<xsl:variable name="JID" select="preceding-sibling::JobId"/>
<xsl:variable name="JTITLE" select="preceding-sibling::JobTitle"/>

並最終將它們作為參數傳遞給命名模板。 整個樣式表如下。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:strip-space elements="*"/>

    <xsl:output indent="yes" omit-xml-declaration="yes"/>

    <xsl:template match="Job/Location">
        <xsl:variable name="JID" select="preceding-sibling::JobId"/>
        <xsl:variable name="JTITLE" select="preceding-sibling::JobTitle"/>
        <xsl:choose>
            <xsl:when test="SubLocations != ''">
                <xsl:for-each select="distinct-values(SubLocations/tokenize(.,','))">
                    <xsl:call-template name="JobRecord">
                        <xsl:with-param name="Location" select="."/>
                        <xsl:with-param name="JobID" select="$JID"/>
                        <xsl:with-param name="JobTITLE" select="$JTITLE"/>
                    </xsl:call-template>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="JobRecord">
                    <xsl:with-param name="Location" select="LocationCode"/>
                    <xsl:with-param name="JobID" select="$JID"/>
                    <xsl:with-param name="JobTITLE" select="$JTITLE"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="JobRecord">
        <xsl:param name="JobID"/>
        <xsl:param name="JobTITLE"/>
        <xsl:param name="Location"/>
        <Id><xsl:value-of select="$JobID"/></Id>
        <Name><xsl:value-of select="$JobTITLE"/></Name>
        <Location><xsl:value-of select="$Location"/></Location>
    </xsl:template>

    <xsl:template match="JobId|JobTitle"/>

</xsl:stylesheet>

XSLT / XPath中僅處理兩個可能元素中的第一個的慣用法是構造一個序列並選擇該序列中的第一個項目,即根據您的情況選擇((SubLocations, LocationCode)[1]) ,因為您可以通過以下方式獲取元素SubLocations如果存在),否則獲取元素LocationCode 然后,您可以標記化並將結果發送到另一個模板,而不是使用call-template我只是建議將元素Job推到與命名模式匹配的另一個模板:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    expand-text="yes"
    version="3.0">

  <xsl:output omit-xml-declaration="yes"/>

  <xsl:template match="Job">
      <xsl:variable name="job" select="."/>
      <xsl:for-each select="Location/tokenize((SubLocations, LocationCode)[1], ',')">
          <xsl:apply-templates select="$job" mode="row">
              <xsl:with-param name="loc" select="current()"/>
          </xsl:apply-templates>
      </xsl:for-each>
  </xsl:template>

  <xsl:template match="Job" mode="row">
      <xsl:param name="loc"/>
      <Id>{JobId}</Id>
      <Title>{JobTitle}</Title>
      <Location>{$loc}</Location>
      <xsl:text>&#10;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

這是一個與Saxon 9.8所有版本一起使用的XSLT 3示例,可以從http://xsltfiddle.liberty-development.net/bFukv8i在線獲得,但是當然可以通過將最后一個模板更改為XSLT 2來進行調整。

  <xsl:template match="Job" mode="row">
      <xsl:param name="loc"/>
      <Id>
        <xsl:value-of select="JobId"/>
      </Id>
      <Title>
          <xsl:value-of select="JobTitle"/>
      </Title>
      <Location>
          <xsl:value-of select="$loc"/>
      </Location>
      <xsl:text>&#10;</xsl:text>
  </xsl:template>

並刪除xsl:stylesheet上的expand-text屬性, http xsl:stylesheet //xsltransform.hikmatu.com/eiQZDbi

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM