Cannot Get XSLT IF To Return Xml
I want to copy the elements that match when
SECURITY_TYPE = 1 and SECURITY_SUB_TYPE = 99
OR
SECURITY_TYPE = 1 and SECURITY_SUB_TYPE = 12
Here is a snippet of the`XML
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>F</TICKER>
<SECURITY_TYPE>1</SECURITY_TYPE>
<SECURITY_SUB_TYPE>99</SECURITY_SUB_TYPE>
<PRICE>17.98</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>C</TICKER>
<SECURITY_TYPE>1</SECURITY_TYPE>
<SECURITY_SUB_TYPE>12</SECURITY_SUB_TYPE>
<PRICE>3.42</PRICE>
<QUAN开发者_C百科TITY>1</QUANTITY>
</trade>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>AAPL</TICKER>
<SECURITY_TYPE>2</SECURITY_TYPE>
<SECURITY_SUB_TYPE>4</SECURITY_SUB_TYPE>
<PRICE>300.34</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
Here is my failed XSLT. What could be wrong?
<?xml version="1.0" encoding="utf-8"?>
<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:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:if test="(SECURITY_TYPE = 1 and SECURITY_SUB_TYPE = 99) or
(SECURITY_TYPE = 1 and SECURITY_SUB_TYPE = 12)">
<xsl:value-of select="."/>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
It seemes that you are trying to produce something like the identity rule, but you are missing the <xsl:apply-templates>
part and your transformation does not go deeper at all.
Here is a short and easy solution:
<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=
"trade[not(SECURITY_TYPE = 1)
or
(not(SECURITY_SUB_TYPE = 99)
and
not(SECURITY_SUB_TYPE = 12)
)
]"/>
</xsl:stylesheet>
when this transformation is applied on the provided XML document (wrapped by a single top element to make it well-formed):
<t>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>F</TICKER>
<SECURITY_TYPE>1</SECURITY_TYPE>
<SECURITY_SUB_TYPE>99</SECURITY_SUB_TYPE>
<PRICE>17.98</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>C</TICKER>
<SECURITY_TYPE>1</SECURITY_TYPE>
<SECURITY_SUB_TYPE>12</SECURITY_SUB_TYPE>
<PRICE>3.42</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>AAPL</TICKER>
<SECURITY_TYPE>2</SECURITY_TYPE>
<SECURITY_SUB_TYPE>4</SECURITY_SUB_TYPE>
<PRICE>300.34</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
</t>
the wanted, correct result is produced:
<t>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>F</TICKER>
<SECURITY_TYPE>1</SECURITY_TYPE>
<SECURITY_SUB_TYPE>99</SECURITY_SUB_TYPE>
<PRICE>17.98</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>C</TICKER>
<SECURITY_TYPE>1</SECURITY_TYPE>
<SECURITY_SUB_TYPE>12</SECURITY_SUB_TYPE>
<PRICE>3.42</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
</t>
Explanation:
The identity rule (template) copies all nodes "as-is". Using and overriding the identity rule is the most fundamental XSLT design pattern.
There is a single additional template that overrides the identity rule for any
trade
element that doesn't satisfy the required selection properties. This template has no body and thus it causes the transformation not to process at all (delete) anytrade
element that doesn't satisfy the required conditions.As result of 1. and 2. above, only
trade
elements (and their complete sub-trees) that satisfy the required conditions are copied to the output.
Use the identity transformation template plus one template suppressing copying of the elements not matching the condition:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="trade[not((SECURITY_TYPE = 1 and SECURITY_SUB_TYPE = 99) or (SECURITY_TYPE = 1 and SECURITY_SUB_TYPE = 12))]"/>
If that does not do what you want then post the result you want to achieve.
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="trade[SECURITY_TYPE != 1
or SECURITY_SUB_TYPE != 99
and SECURITY_SUB_TYPE != 12]"/>
</xsl:stylesheet>
Output: (with wellformed input, of course):
<root>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>F</TICKER>
<SECURITY_TYPE>1</SECURITY_TYPE>
<SECURITY_SUB_TYPE>99</SECURITY_SUB_TYPE>
<PRICE>17.98</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
<trade>
<PORTFOLIO_NUMBER>123</PORTFOLIO_NUMBER>
<TICKER>C</TICKER>
<SECURITY_TYPE>1</SECURITY_TYPE>
<SECURITY_SUB_TYPE>12</SECURITY_SUB_TYPE>
<PRICE>3.42</PRICE>
<QUANTITY>1</QUANTITY>
</trade>
</root>
I added a root element of <trades>. The solution below works. You must apply the conditional logic only to the <trade> element, not all elements.
<?xml version="1.0" encoding="utf-8"?>
<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:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<!-- parse the <trade> element -->
<xsl:template match="trade">
<xsl:copy>
<xsl:if test="(SECURITY_TYPE = 1 and SECURITY_SUB_TYPE = 99) or
(SECURITY_TYPE = 1 and SECURITY_SUB_TYPE = 12)">
<xsl:value-of select="."/>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
精彩评论