我最近遇到以下股票代碼XML飼料跑:優化XSLT的
<?xml version="1.0" encoding="utf-8"?>
<BloombergOutput>
<BloombergOutput CreatedUtc="2011-08-11T20:40:50.8851936Z">
<Instruments>
<Instrument Symbol="BLL">
<Fields>
<Field1 Name="LastPrice">
<Value>35.550000</Value>
</Field1>
<Field2 Name="NetChangeOneDay">
<Value>+1.550000</Value>
</Field2>
<Field3 Name="LastCloseDate">
<Value>08/11/2011</Value>
</Field3>
<Field4 Name="LastClosePrice">
<Value>35.550000</Value>
</Field4>
<Field5 Name="UpdateDate">
<Value>08/11/2011</Value>
</Field5>
<Field6 Name="UpdateTime">
<Value>16:15:03</Value>
</Field6>
<Field7 Name="LongName">
<Value>Ball Corp</Value>
</Field7>
<Field8 Name="Name">
<Value>BALL CORP</Value>
</Field8>
<Field9 Name="PriceSource">
<Value>US</Value>
</Field9>
<Field10 Name="SymbolType">
<Value>Common Stock</Value>
</Field10>
</Fields>
</Instrument>
</Instruments>
</BloombergOutput>
</BloombergOutput>
我想用XSLT轉換這種飼料到的東西,沒有多餘的標記嵌套,有更多的描述性元素名稱和截短的過長數字,因此它們只有小數點後面有兩個數字。這是我想出了XSLT:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Identity Transform, modified to begin at the Instruments element -->
<xsl:template match="BloombergOutput/BloombergOutput/Instruments/@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- For each instrument, we grab the Symbol attribute and work on each child element -->
<xsl:template match="Instrument">
<Instrument>
<Symbol><xsl:value-of select="@Symbol" /></Symbol>
<xsl:apply-templates select="Fields/*" mode="fields" />
</Instrument>
</xsl:template>
<!-- For each child field, we create a newly-named one and give it a value -->
<xsl:template match="node()" mode="fields">
<xsl:variable
name="FieldName"
select="@Name" />
<xsl:variable
name="Value"
select="Value" />
<xsl:element name="{$FieldName}">
<xsl:choose>
<!-- For these fields, we only want to preserve to spots after the decimal point -->
<xsl:when test="$FieldName='LastPrice' or $FieldName='NetChangeOneDay' or $FieldName='LastClosePrice'">
<xsl:value-of select="concat(substring-before($Value, '.'), '.', substring(substring-after($Value, '.'), 1, 2))" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$Value" />
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
...產生這樣的輸出:
<?xml version="1.0"?>
<BloombergOutput>
<BloombergOutput>2011-08-11T20:40:50.8851936Z
<Instruments>
<Instrument>
<Symbol>BLL</Symbol>
<LastPrice>35.55</LastPrice>
<NetChangeOneDay>+1.55</NetChangeOneDay>
<LastCloseDate>08/11/2011</LastCloseDate>
<LastClosePrice>35.55</LastClosePrice>
<UpdateDate>08/11/2011</UpdateDate>
<UpdateTime>16:15:03</UpdateTime>
<LongName>Ball Corp</LongName>
<Name>BALL CORP</Name>
<PriceSource>US</PriceSource>
<SymbolType>Common Stock</SymbolType>
</Instrument>
</Instruments>
</BloombergOutput>
</BloombergOutput>
雖然這幾乎是我想要的東西,也有一些問題:
- 的保留頂部額外的
BloombergOutput
元素;此外,其CreatedUtc
參數仍以相當奇怪的方式保留。我最初的意圖是完全刪除不必要的BloombergOutput
標籤。 - 我成功插入了一個
Instrument
標籤。 但是,Instruments
保留,我沒有明確表示如此。 我得到的身份轉換帶來了它,因爲我沒有 告訴它消失,但如果我想要不同的開幕元素 (說,StockQuote
)? - 我的意圖是要善於使用身份變換。 但是,我不確定我的匹配修改是否是正確的 方式來完成我正在做的事情。
總體而言,我正在尋找關於如何改進此問題的專家建議。隨意告訴我,我試圖在不屬於它的設計模式中進行干預。 :)
非常感謝。
謝謝,@Dimitre。我喜歡你的想法。然而,兩個注意事項:(1)當我運行這個轉換(使用xsltproc)時,我得到一個xsl:元素:有效的名稱''不是有效的QName。有關{@Name}值的錯誤; (2)它看起來像一些領域,仍然有一個價值元素 - 我的意圖是擺脫這些,並有價值直接輸出。 – ABach
@ABach:很好。我沒有注意到這一點,因爲Saxon 6.5.4(XSLT 1.0處理器)有一個bug並且轉換成功。現在我用Saxon 9.1.05(XSLT 2.0處理器)運行它。我會盡快更新我的答案。只需使用:'而不是' @ –
@ABach:更新了我的答案。 –