2016-04-21 95 views
1

我在xml文檔中有一組兄弟元素需要用XSLT處理到表中,實際上我使用Apache FOP將其轉換爲pdf。需要在遇到兩種類型的元素之一時創建錶行。該行中的單元格由導致在第一個單元格中創建該行的元素以及後續單元格中的後續兄弟元素組成,直到導致創建行的下一個元素。下面是一些示例性的XML,以更好地解釋:如何使用XPath和XSLT處理一組兄弟節點並基於兩個兄弟處理特定的兄弟姐妹子集

<pre class="prettyprint"><code class="language-xml"> 
     <reqpers> 
      <person man="Four"/> 

      <person man="A" id="pers_a"/> 
      <perscat category="Recovery Supervisor"/> 

      <person man="B" id="pers_b"/> 
      <perscat category="Ground Personnel"/> 

      <asrequir/> 
      <perscat category="As Required Category"/> 
      <trade>Bill Collector</trade> 

      <person man="C" id="pers_c"/> 
      <perscat category="Ground Personnel"/> 
      <perskill skill="sk01"/> 
      <trade>welder</trade> 
      <esttime>.5 hr</esttime> 

      <asrequir/> 
      <perscat category="2nd Required Category"/> 
      <esttime>4 days</esttime> 

      <person man="D" id="pers_d"/> 
      <perscat category="Rides in Chase Vehicle"/> 
      <perskill skill="sk02"/> 

      <person man="E"/> 
      <perscat category="Jack of all Trades"/> 
      <trade>engine mechanic</trade> 
    </reqpers> 
    </code> 
    </pre> 

甲行需要爲每個人或asrequir元件,然後將細胞用於填充組這些元件之間的兄弟姐妹的行被創建。 我已經看過很多例子,包括:How to select siblings

這一個:How to select group of siblings

以及許多其他的。這些都不涉及我的具體問題集,這主要是在XPath查詢中有兩個以下的兄弟姐妹需要處理。 這裏的表應該是什麼樣子的例子:

<pre class="prettyprint"><code class="language-xml"> 
    <table> 
     <table-header> 
      <table-row> 
       <table-cell> Person </table-cell> 
       <table-cell> Category/Trade </table-cell> 
       <table-cell> Skill level </table-cell> 
       <table-cell> Trade code </table-cell> 
       <table-cell> Estimated time </table-cell> 
      </table-row> 
     </table-header> 
     <table-body> 
      <table-row> 
       <table-cell>Four</table-cell> 
       <table-cell/> 
       <table-cell/> 
       <table-cell/> 
       <table-cell/> 
      </table-row> 
      <table-row> 
       <table-cell>A</table-cell> 
       <table-cell>Recovery Supervisor</table-cell> 
       <table-cell/> 
       <table-cell/> 
       <table-cell/> 
      </table-row> 
      <table-row> 
       <table-cell>B</table-cell> 
       <table-cell>Ground Personnel</table-cell> 
       <table-cell/> 
       <table-cell/> 
       <table-cell/> 
      </table-row> 
      <table-row> 
       <table-cell>As required</table-cell> 
       <table-cell/> 
       <table-cell/> 
       <table-cell>Bill Collector</table-cell> 
       <table-cell/> 
      </table-row> 
      <table-row> 
       <table-cell>C</table-cell> 
       <table-cell>Ground Personnel</table-cell> 
       <table-cell>skill gets converted to string value</table-cell> 
       <table-cell>welder</table-cell> 
       <table-cell>.5 hr</table-cell> 
      </table-row> 
      <table-row> 
       <table-cell>As required</table-cell> 
       <table-cell>2nd Required Category</table-cell> 
       <table-cell/> 
       <table-cell/> 
       <table-cell>4 days</table-cell> 
      </table-row> 
      <table-row> 
       <table-cell>D</table-cell> 
       <table-cell>Rides in Chase Vehicle</table-cell> 
       <table-cell>skill level</table-cell> 
       <table-cell/> 
       <table-cell/> 
      </table-row> 
      <table-row> 
       <table-cell>E</table-cell> 
       <table-cell>Jack of all Trades</table-cell> 
       <table-cell/> 
       <table-cell>engine mechanic</table-cell> 
       <table-cell/> 
      </table-row> 
     </table-body> 
    </table> 
</code> 
     </pre> 

同樣的完整性,這是對XML架構片斷我處理:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
<xs:element name="reqpers" type="reqpersType"/> 
<xs:complexType name="reqpersType"> 
    <xs:sequence> 
     <xs:element minOccurs="0" ref="applic"/> 
     <xs:sequence maxOccurs="unbounded"> 
      <xs:choice> 
       <xs:element ref="asrequir"/> 
       <xs:element ref="person"/> 
      </xs:choice> 
      <xs:sequence minOccurs="0"> 
       <xs:element ref="perscat"/> 
       <xs:element minOccurs="0" ref="perskill"/> 
       <xs:element minOccurs="0" ref="trade"/> 
       <xs:element minOccurs="0" ref="esttime"/> 
      </xs:sequence> 
     </xs:sequence> 
    </xs:sequence> 
    <xs:attribute ref="refapplic"/> 
    <xs:attributeGroup ref="bodyatt"/> 
    <xs:attributeGroup ref="cntlcontent"/> 
</xs:complexType> 

這裏是一個最接近的xsl代碼的例子,但它只適用於有人的兄弟姐妹,一旦asrequir被添加的東西分崩離析。我基本上重複每個單元格的代碼,用我期望的元素替換perscat。

<xsl:for-each select="person | asrequir"> 
      <fo:table-row> 
       <fo:table-cell text-align="left" padding-before="1mm" padding-after="1mm" padding-left="1mm" padding-right="1mm"> 
        <fo:block font-size="10pt"> 
         <xsl:value-of select="self::person/@man"/> 
        </fo:block> 
       </fo:table-cell> 
    <fo:table-cell text-align="left" padding-before="1mm" padding-after="1mm" padding-left="1mm" padding-right="1mm"> 
     <xsl:variable name="perscatSib" select="following-sibling::perscat"/> 
     <xsl:variable name="perscatPrec" select="following-sibling::person[1]/preceding-sibling::perscat"/> 
     <fo:block font-size="10pt"> 
      <xsl:choose> 
       <xsl:when test="$perscatSib[count(. | $perscatPrec) = count($perscatPrec)]"> 
        <xsl:value-of select="$perscatSib[count(. | $perscatPrec) = count($perscatPrec)]/@category"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:if test="preceding-sibling::person[1] and not(following-sibling::person[1])"> 
         <xsl:value-of select="following-sibling::perscat[1]/@category"/> 
        </xsl:if> 
       </xsl:otherwise> 
      </xsl:choose> 
     </fo:block> 
    </fo:table-cell> 
<continues with the rest of the cells../> 

這是我製作的表格:

<pre class="prettyprint"><code class="language-xml"> 
<table> 
    <table-header> 
     <table-row> 
      <table-cell> Person </table-cell> 
      <table-cell> Category/Trade </table-cell> 
      <table-cell> Skill level </table-cell> 
      <table-cell> Trade code </table-cell> 
      <table-cell> Estimated time </table-cell> 
     </table-row> 
    </table-header> 
    <table-body> 
     <table-row> 
      <table-cell>Four</table-cell> 
      <table-cell/> 
      <table-cell/> 
      <table-cell/> 
      <table-cell/> 
     </table-row> 
     <table-row> 
      <table-cell>A</table-cell> 
      <table-cell>Recovery Supervisor</table-cell> 
      <table-cell/> 
      <table-cell/> 
      <table-cell/> 
     </table-row> 
     <table-row> 
      <table-cell>B</table-cell> 
      <table-cell>Ground Personnel</table-cell> 
      <table-cell/> 
      **<table-cell>BillCollector</table-cell>** 
      <table-cell/> 
     </table-row> 
     <table-row> 
      <table-cell>As required</table-cell> 
      <table-cell/> 
      <table-cell/> 
      <table-cell>Bill Collector</table-cell> 
      <table-cell/> 
     </table-row> 
     <table-row> 
      <table-cell>C</table-cell> 
      <table-cell>Ground Personnel</table-cell> 
      <table-cell>skill gets converted to string value</table-cell> 
      <table-cell>welder</table-cell> 
      <table-cell>.5 hr</table-cell> 
     </table-row> 
     <table-row> 
      <table-cell>As required</table-cell> 
      <table-cell>2nd Required Category</table-cell> 
      <table-cell/> 
      <table-cell/> 
      <table-cell>4 days</table-cell> 
     </table-row> 
     <table-row> 
      <table-cell>D</table-cell> 
      <table-cell>Rides in Chase Vehicle</table-cell> 
      <table-cell>skill level</table-cell> 
      <table-cell/> 
      <table-cell/> 
     </table-row> 
     <table-row> 
      <table-cell>E</table-cell> 
      <table-cell>Jack of all Trades</table-cell> 
      <table-cell/> 
      <table-cell>engine mechanic</table-cell> 
      <table-cell/> 
     </table-row> 
    </table-body> 
</table> 
</code> 
     </pre> 

與**的表格單元格周圍不應該有它的數據。它增加了從以下asrequir這是不是值我想要什麼..

我已經嘗試添加以下 - 兄弟::人['1'] | asrequir ['1']但asrequir總是如此,所以我得到額外的兄弟姐妹在我不想要的地方。任何有關如何解決這個問題的見解或建議將非常感謝。我懷疑我需要使用某種類別的密鑰或密鑰集合,但不知道如何實現這些。雖然不是XSLT和XPath的新手,但我不是專家。

+1

您可以使用XSLT 2.0和-各組組啓動,用? –

+0

現在我暫時停留在XSLT 1.0中。 –

回答

2

一個密鑰可以幫助將來自reqpers的非person or asrequir的所有元素分組到前兄弟姐妹或asrequir。

<xsl:for-each select="*[self::person or self::asrequir]"> 

小組成員則:

<xsl:variable name="this" select="." /> 
    <xsl:variable name="group" select=". | key('kperson',generate-id($this))" /> 

從組獲取的值:

<xsl:value-of select="$group[self::perscat]/@category"/> 

你可以試試這個

<xsl:key name="kperson" match="reqpers/*[not(self::person or self::asrequir)]" 
     use="generate-id(preceding-sibling::*[self::person or self::asrequir][1]) 

與本集團統計:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:key name="kperson" match="reqpers/*[not(self::person or self::asrequir)]" 
      use="generate-id(preceding-sibling::*[self::person or self::asrequir][1])"/> 
    <xsl:template match="reqpers"> 
    <table> 
    <table-header> 
     <table-row> 
      <table-cell> Person </table-cell> 
      <table-cell> Category/Trade </table-cell> 
      <table-cell> Skill level </table-cell> 
      <table-cell> Trade code </table-cell> 
      <table-cell> Estimated time </table-cell> 
     </table-row> 
    </table-header> 
    <xsl:for-each select="*[self::person or self::asrequir]"> 

     <xsl:variable name="this" select="." /> 
     <xsl:variable name="group" select=". | key('kperson',generate-id($this))" /> 
     <table-row> 
      <table-cell> 
       <xsl:value-of select="$group[self::person]/@man"/> 
       <xsl:if test="$group[self::asrequir]" >As required</xsl:if> 
      </table-cell> 
      <table-cell><xsl:value-of select="$group[self::perscat]/@category"/></table-cell> 
      <table-cell><xsl:value-of select="$group[self::perskill]/@skill"/></table-cell> 
      <table-cell><xsl:value-of select="$group[self::trade]"/></table-cell> 
      <table-cell><xsl:value-of select="$group[self::esttime]"/></table-cell> 
     </table-row> 
    </xsl:for-each> 
    </table> 
    </xsl:template> 

</xsl:stylesheet> 

有了以下的輸出:

<table> 
    <table-header> 
    <table-row> 
     <table-cell> Person </table-cell> 
     <table-cell> Category/Trade </table-cell> 
     <table-cell> Skill level </table-cell> 
     <table-cell> Trade code </table-cell> 
     <table-cell> Estimated time </table-cell> 
    </table-row> 
    </table-header> 
    <table-row> 
    <table-cell>Four</table-cell> 
    <table-cell/> 
    <table-cell/> 
    <table-cell/> 
    <table-cell/> 
    </table-row> 
    <table-row> 
    <table-cell>A</table-cell> 
    <table-cell>Recovery Supervisor</table-cell> 
    <table-cell/> 
    <table-cell/> 
    <table-cell/> 
    </table-row> 
    <table-row> 
    <table-cell>B</table-cell> 
    <table-cell>Ground Personnel</table-cell> 
    <table-cell/> 
    <table-cell/> 
    <table-cell/> 
    </table-row> 
    <table-row> 
    <table-cell>As required</table-cell> 
    <table-cell>As Required Category</table-cell> 
    <table-cell/> 
    <table-cell>Bill Collector</table-cell> 
    <table-cell/> 
    </table-row> 
    <table-row> 
    <table-cell>C</table-cell> 
    <table-cell>Ground Personnel</table-cell> 
    <table-cell>sk01</table-cell> 
    <table-cell>welder</table-cell> 
    <table-cell>.5 hr</table-cell> 
    </table-row> 
    <table-row> 
    <table-cell>As required</table-cell> 
    <table-cell>2nd Required Category</table-cell> 
    <table-cell/> 
    <table-cell/> 
    <table-cell>4 days</table-cell> 
    </table-row> 
    <table-row> 
    <table-cell>D</table-cell> 
    <table-cell>Rides in Chase Vehicle</table-cell> 
    <table-cell>sk02</table-cell> 
    <table-cell/> 
    <table-cell/> 
    </table-row> 
    <table-row> 
    <table-cell>E</table-cell> 
    <table-cell>Jack of all Trades</table-cell> 
    <table-cell/> 
    <table-cell>engine mechanic</table-cell> 
    <table-cell/> 
    </table-row> 
</table>