2011-01-28 23 views
0

我想優化下面的XSL轉換。我已經包含了示例輸入數據,並且創建了示例輸出。輸入數據來自數據庫,每行有記錄元素,並且每個列的子元素都被選中。可以有任意數量的任意列的任何名稱的列。我不知道任何提前(除了Id元素)。我需要將該數據轉換爲定義所用列的網格XML格式,然後包括每個記錄的個元素以及每個列的個元素個元素。輸入數據包括其子元素定義需要出現在輸出中的列的元素。我不知道任何列可能會提前。需要在輸出中出現下的所有元素。輸出中列/單元格的順序由子元素中的命令屬性決定。 記錄匹配列的子元素列子元素在輸出中提供相應的單元格元素的數據。 記錄沒有匹配的子元素子元素被忽略。並非全部子元素將對應記錄子元素;對他們來說,我們需要輸出一個空的單元格元素。我可以優化此XSL轉換,它將未知列的記錄轉換爲網格格式嗎?

我可以讓這個XSL工作更好嗎?我知道每個人都是「壞」的。我可以模板化這個嗎?謝謝!

XML輸入:

<?xml version="1.0" encoding="utf-8" ?> 
<!-- The root element could have any name --> 
<Data> 
    <!-- There could be any number of Record elements --> 
    <Record> 
     <!-- Elements here may have any name and be in any order and may not be included in Columns --> 
     <!-- For a particular XML file, all Record elements have the same child elements in the same order --> 
     <Id>234542</Id> 
     <Name>Tom Winter</Name> 
     <SSN>XXX-XX-3317</SSN> 
     <Facility>East Coast Hospital</Facility> 
     <Status>AC</Status> 
    </Record> 
    <Record> 
     <Id>345223</Id> 
     <Name>John Doe</Name> 
     <SSN>XXX-XX-2344</SSN> 
     <Facility>St. Joseph West</Facility> 
     <Status>DE</Status> 
    </Record> 
    <Columns> 
     <!-- There may be any number of element here and they can be in any order --> 
     <Name label="Patient Name" display="yes" order="2"/> 
     <MRN label="MRN #" display="yes" order="1"/> 
     <BirthDate label="Birth Date" align="right" display="yes" order="3"/> 
     <SSN label="SSN" display="yes" order="9" notSortable="yes"/> 
     <DischargeDate label="Discharge Date" align="right" display="no" order="7"/> 
     <Address label="Address" display="yes" order="8"/> 
     <Facility label="Facility" display="yes" order="4"/> 
    </Columns> 
</Data> 

XSL:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" encoding="utf-8"/> 
    <xsl:key name="recordId" match="Record" use="generate-id(.)"/> 
    <xsl:template match="/*"> 
     <grid name="exampleGrid"> 
      <xsl:for-each select="//Columns/*"> 
       <xsl:sort select="@order" order="ascending" data-type="number"/> 
       <xsl:variable name="name" select="local-name(.)"/> 
       <column label="{@label}" name="{$name}" align="{@align}"/> 
      </xsl:for-each> 
      <xsl:for-each select="Record"> 
       <xsl:call-template name="Record"/> 
      </xsl:for-each> 
     </grid> 
    </xsl:template> 
    <xsl:template name="Record"> 
     <xsl:variable name="recordId" select="generate-id(.)"/> 
     <row key="{Id}"> 
      <xsl:for-each select="//Columns/*"> 
       <xsl:sort select="@order" order="ascending" data-type="number"/> 
       <xsl:variable name="name" select="local-name(.)"/> 
       <cell align="{@align}"> 
        <xsl:value-of select="key('recordId', $recordId)/*[local-name(.) = $name]"/> 
       </cell> 
      </xsl:for-each> 
     </row> 
    </xsl:template> 
</xsl:stylesheet> 

XML輸出:

<grid name="exampleGrid"> 
    <column label="MRN #" name="MRN" align="" /> 
    <column label="Patient Name" name="Name" align="" /> 
    <column label="Birth Date" name="BirthDate" align="right" /> 
    <column label="Facility" name="Facility" align="" /> 
    <column label="Discharge Date" name="DischargeDate" align="right" /> 
    <column label="Address" name="Address" align="" /> 
    <column label="SSN" name="SSN" align="" /> 
    <row key="234542"> 
     <cell align=""></cell> 
     <cell align="">Tom Winter</cell> 
     <cell align="right"></cell> 
     <cell align="">East Coast Hospital</cell> 
     <cell align="right"></cell> 
     <cell align=""></cell> 
     <cell align="">XXX-XX-3317</cell> 
    </row> 
    <row key="345223"> 
     <cell align=""></cell> 
     <cell align="">John Doe</cell> 
     <cell align="right"></cell> 
     <cell align="">St. Joseph West</cell> 
     <cell align="right"></cell> 
     <cell align=""></cell> 
     <cell align="">XXX-XX-2344</cell> 
    </row> 
</grid> 
+2

使用您的XSLT 1.0處理器,您可以使用擴展功能,例如`exsl:node-set`嗎?在這種情況下,我建議只對「Columns/*」進行一次排序,將結果存儲在結果樹片段中,將其轉換爲具有擴展函數的節點集,全局變量中完成的所有操作,然後使用變量與排序的節點,而不是一次又一次排序。 – 2011-01-28 15:35:27

+0

@Martin Honnen:+1好的建議。 – 2011-01-28 15:52:26

回答

3

這是我會怎麼做這個任務:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:variable name="vColumns" select="/*/Columns/*"/> 
    <xsl:template match="/*"> 
     <grid name="exampleGrid"> 
      <xsl:apply-templates select="$vColumns"> 
       <xsl:sort select="@order" data-type="number"/> 
      </xsl:apply-templates> 
      <xsl:apply-templates select="Record"/> 
     </grid> 
    </xsl:template> 
    <xsl:template match="Columns/*"> 
     <column label="{@label}" name="{local-name()}" align="{@align}"/> 
    </xsl:template> 
    <xsl:template match="Record"> 
     <xsl:variable name="vCurrent" select="."/> 
     <row key="{Id}"> 
      <xsl:for-each select="$vColumns"> 
       <xsl:sort select="@order" data-type="number"/> 
       <cell align="{@align}"> 
        <xsl:value-of 
         select="$vCurrent/*[local-name() 
               = local-name(current())]"/> 
       </cell> 
      </xsl:for-each> 
     </row> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<grid name="exampleGrid"> 
    <column label="MRN #" name="MRN" align="" /> 
    <column label="Patient Name" name="Name" align="" /> 
    <column label="Birth Date" name="BirthDate" align="right" /> 
    <column label="Facility" name="Facility" align="" /> 
    <column label="Discharge Date" name="DischargeDate" align="right" /> 
    <column label="Address" name="Address" align="" /> 
    <column label="SSN" name="SSN" align="" /> 
    <row key="234542"> 
     <cell align=""></cell> 
     <cell align="">Tom Winter</cell> 
     <cell align="right"></cell> 
     <cell align="">East Coast Hospital</cell> 
     <cell align="right"></cell> 
     <cell align=""></cell> 
     <cell align="">XXX-XX-3317</cell> 
    </row> 
    <row key="345223"> 
     <cell align=""></cell> 
     <cell align="">John Doe</cell> 
     <cell align="right"></cell> 
     <cell align="">St. Joseph West</cell> 
     <cell align="right"></cell> 
     <cell align=""></cell> 
     <cell align="">XXX-XX-2344</cell> 
    </row> 
</grid> 

只有一個由Martin Honnen的建議進行排序:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
exclude-result-prefixes="msxsl"> 
    <xsl:variable name="vRTFColumns"> 
     <xsl:for-each select="/*/Columns/*"> 
      <xsl:sort select="@order" data-type="number"/> 
      <xsl:copy-of select="."/> 
     </xsl:for-each> 
    </xsl:variable> 
    <xsl:variable name="vColumns" 
        select="msxsl:node-set($vRTFColumns)/*"/> 
    <xsl:template match="/*"> 
     <grid name="exampleGrid"> 
      <xsl:for-each select="$vColumns"> 
       <column label="{@label}" 
         name="{local-name()}" 
         align="{@align}"/> 
      </xsl:for-each> 
      <xsl:apply-templates select="Record"/> 
     </grid> 
    </xsl:template> 
    <xsl:template match="Record"> 
     <xsl:variable name="vCurrent" select="."/> 
     <row key="{Id}"> 
      <xsl:for-each select="$vColumns"> 
       <cell align="{@align}"> 
        <xsl:value-of 
         select="$vCurrent/*[local-name() 
               = local-name(current())]"/> 
       </cell> 
      </xsl:for-each> 
     </row> 
    </xsl:template> 
</xsl:stylesheet> 

EDIT:添加XSLT 2.0解決方案,因爲是xsl:perform-sort指令的很好的例子。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:variable name="vColumns" as="element()*"> 
     <xsl:perform-sort select="/*/Columns/*"> 
      <xsl:sort select="@order" data-type="number"/> 
     </xsl:perform-sort> 
    </xsl:variable> 
    <xsl:template match="/*"> 
     <grid name="exampleGrid"> 
      <xsl:apply-templates select="$vColumns"/> 
      <xsl:apply-templates select="Record"/> 
     </grid> 
    </xsl:template> 
    <xsl:template match="Columns/*"> 
     <column label="{@label}" name="{local-name()}" align="{@align}"/> 
    </xsl:template> 
    <xsl:template match="Record"> 
     <xsl:variable name="vCurrent" select="."/> 
     <row key="{Id}"> 
      <xsl:for-each select="$vColumns"> 
       <cell align="{@align}"> 
        <xsl:value-of 
         select="$vCurrent/*[local-name() 
              = local-name(current())]"/> 
       </cell> 
      </xsl:for-each> 
     </row> 
    </xsl:template> 
</xsl:stylesheet> 

注意:在$vColumns序列節點保留自己的身份,現在我們可以使用模式與之匹配。