Xml 使用身份转换优化XSLT
我最近遇到了以下股票代码XML提要:Xml 使用身份转换优化XSLT,xml,xslt,Xml,Xslt,我最近遇到了以下股票代码XML提要: <?xml version="1.0" encoding="utf-8"?> <BloombergOutput> <BloombergOutput CreatedUtc="2011-08-11T20:40:50.8851936Z"> <Instruments> <Instrument Symbol="BLL"> <Fields>
<?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>
35.550000
+1.550000
08/11/2011
35.550000
08/11/2011
16:15:03
鲍尔公司
鲍尔公司
美国
普通股
我想使用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>
2011-08-11T20:40:50.8851936Z
BLL
35.55
+1.55
08/11/2011
35.55
08/11/2011
16:15:03
鲍尔公司
鲍尔公司
美国
普通股
虽然这几乎是我想要的,但也存在一些问题:
BloombergOutput
元素被保留;此外,它的CreatedUtc
参数以一种非常奇怪的方式保留。我的初衷是完全删除不必要的BloombergOutput
标记仪器
标签。
但是,仪器
在我未明确说明的情况下保留。
我知道身份转换带来了它,因为我没有
告诉它走开,但是如果我想要不同的开场元素呢
(比如,StockQuote
)非常感谢。我想这是您正在寻找的机制:
<?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="*"/>
<!-- Get rid of the BloombergOutput, Instruments elements-->
<xsl:template match="BloombergOutput|Instruments">
<xsl:apply-templates/>
</xsl:template>
<!-- Identity Transform -->
<xsl:template match="@*|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/*" />
</Instrument>
</xsl:template>
<!-- For each child field, we create a newly-named one and give it a value -->
<xsl:template match="*[starts-with(name(),'Field')]">
<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>
还有一句话,如果你有两个仪器
元素,那么转换的结果将不会很好。好问题,+1
这里有一个更简单、更短、更简洁的解决方案(没有变量,没有xsl:choose
/xsl:when
/xsl:when
/否则,没有子字符串()
):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BloombergOutput | Fields" priority="2">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*[starts-with(name(),'Field')]">
<xsl:element name="{@Name}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="Value">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match=
"*[contains('|LastPrice|LastClosePrice|NetChangeOneDay|',
concat('|', @Name, '|')
)
]
/Value
">
<xsl:value-of select=
"format-number(translate(.,'+', ''), '##0.00')"/>
</xsl:template>
</xsl:stylesheet>
将此转换应用于提供的XML文档时:
<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>
<Instruments>
<Instrument Symbol="BLL">
<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>
35.550000
+1.550000
08/11/2011
35.550000
08/11/2011
16:15:03
鲍尔公司
鲍尔公司
美国
普通股
生成所需的正确结果:
<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>
<Instruments>
<Instrument Symbol="BLL">
<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>
35.55
1.55
08/11/2011
35.55
08/11/2011
16:15:03
鲍尔公司
鲍尔公司
美国
普通股
谢谢您的回复。问题:为什么多个Instrument
元素会导致格式不正确的结果?当您匹配Instruments元素时,您只有apply模板。这意味着对于每个工具子级,将触发模板工具,而不触发任何嵌入元素。您可以将测试(使用xsl:choose)添加到模板:if count(*)>1,然后创建一个englobing元素并在其中应用模板,否则只需apply-templates即可。谢谢,@Dimitre。我喜欢你的想法。但是,有两个注意事项:(1)当我运行此转换(使用xsltproc)时,我得到一个xsl:element:有效名称“”不是有效的QName。关于{@Name}值的错误;(2) 看起来对于某些字段,仍然有一个value元素——我的意图是去掉这些元素,并直接输出值。@ABach:很好。我没有注意到这一点,因为Saxon6.5.4(XSLT1.0处理器)有一个bug,并且转换成功。现在我使用Saxon 9.1.05(XSLT2.0处理器)运行它。我很快会更新我的答案。只需使用:``而不是``谢谢-这就解决了这个问题。最后一个呢(其中有我想要删除的无关的
元素)?我希望所有字段都遵循
的格式(而不是,比如说,
)。非常感谢您的帮助。@ABach:我现在正在工作--请耐心等待--我会在5-6小时后调查此事。@ABach:我的理解正确吗?您想要的是:普通股而不是:普通股