问题
I want to create a table Which contain two columns as product type and number of quantity in XSL-Fo. In the XML input file Type node contain 00 then in the table the product should be come like "Other"
if Type element value is
00 then "Other" like wise
51 = Business Loan – General
05 = Personal Loan
I want to see all product in alphabetical ascending odder.
This is my Input XML
<product>
<months>
<Type>00</Type>
<Number>2</Number>
</months>
<months>
<Type>51</Type>
<Number>2</Number>
</months>
<months>
<Type>05</Type>
<Number>1</Number>
</months>
</product>
I tried this Here
quantity
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block >Product Type</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Quantity</fo:block>
</fo:table-cell>
<xsl:for-each select=" Product/months">
<xsl:variable name="Variable" select="Type"></xsl:variable>
<fo:table-row>
<fo:table-cell>
<fo:block >
<xsl:choose>
<xsl:when test="Type[contains(text(),'05')]">
Personal Loan
</xsl:when>
<xsl:when test="ProductType[contains(text(),'55')]">
Business Loan – General
</xsl:when>
<xsl:when test="ProductType[contains(text(),'00')]">
Other
</xsl:when>
</xsl:choose>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="Number"/>
</fo:block>
</fo:table-cell>
</xsl:for-each>
</fo:table-body>
</fo:table>
I got the O/p like below
Product Type | Quantity
-----------------------------------------------------------
Other | 2
Business Loan – General | 2
Personal Loan | 1
but Actual Expected OUT/PUT is this
Product Type | Quantity
-----------------------------------------------------------
Business Loan – General | 2
Other | 2
Personal Loan | 1
回答1:
If can use XSLT 2.0, you can create a variable to hold elements that represent your mappings
<xsl:variable name="products">
<map-entry key="05">Personal Loan</map-entry>
<map-entry key="51">Business Loan – General</map-entry>
<map-entry key="00">Other</map-entry>
</xsl:variable>
Then you can use a key to look these up by the key
attribute
<xsl:key name="map" match="map-entry" use="@key" />
You would then use this key in a sort, like so:
<xsl:for-each select="product/months">
<xsl:sort select="key('map', Type, $products)" />
(As an aside, do make sure you use the correct case, as in your XSLT you were using Product
, not product
)
Try this XSLT, which you can see in action at http://xsltfiddle.liberty-development.net/pPzifoQ
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="products">
<map-entry key="05">Personal Loan</map-entry>
<map-entry key="51">Business Loan – General</map-entry>
<map-entry key="00">Other</map-entry>
</xsl:variable>
<xsl:key name="map" match="map-entry" use="@key" />
<xsl:template match="/">
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>Product Type</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Quantity</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="product/months">
<xsl:sort select="key('map', Type, $products)" />
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="key('map', Type, $products)" />
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="Number"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
</xsl:stylesheet>
Note, if you can use XSLT 3.0, there is a dedicated "map" function you can use, which slightly simplifies things
Try this XSLT 3.0, which you can see in action at http://xsltfiddle.liberty-development.net/bnnZVx
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="xs"
version="3.0">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="products" as="map(xs:string, xs:string)">
<xsl:map>
<xsl:map-entry key="'05'" select="'Personal Loan'"/>
<xsl:map-entry key="'51'" select="'Business Loan – General'"/>
<xsl:map-entry key="'00'" select="'Other'"/>
</xsl:map>
</xsl:variable>
<xsl:template match="/">
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>Product Type</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Quantity</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="product/months">
<xsl:sort select="$products(Type)" />
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="$products(Type)" />
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="Number"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
</xsl:stylesheet>
回答2:
There are several ways you could look at this. For example, you could avoid sorting altogether - esp. if you only have 3 possible product types - by applying templates to each type in turn.
Here's a simplified example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/product">
<table>
<tr>
<th>Product Type</th>
<th>Quantity</th>
</tr>
<xsl:apply-templates select="months[Type='51']"/>
<xsl:apply-templates select="months[Type='00']"/>
<xsl:apply-templates select="months[Type='05']"/>
</table>
</xsl:template>
<xsl:template match="months">
<tr>
<td>
<xsl:choose>
<xsl:when test="Type='51'">Business Loan – General</xsl:when>
<xsl:when test="Type='05'">Personal Loan</xsl:when>
<xsl:when test="Type='00'">Other</xsl:when>
</xsl:choose>
</td>
<td>
<xsl:value-of select="Number"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Another option is to sort by custom order - again, using the codes in their intended order:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/product">
<table>
<tr>
<th>Product Type</th>
<th>Quantity</th>
</tr>
<xsl:variable name="sort-order">|51|00|05|</xsl:variable>
<xsl:for-each select="months">
<xsl:sort select="string-length(substring-before($sort-order, concat('|', Type, '|')))" data-type="number"/>
<tr>
<td>
<xsl:choose>
<xsl:when test="Type='51'">Business Loan – General</xsl:when>
<xsl:when test="Type='05'">Personal Loan</xsl:when>
<xsl:when test="Type='00'">Other</xsl:when>
</xsl:choose>
</td>
<td>
<xsl:value-of select="Number"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
来源:https://stackoverflow.com/questions/54080555/how-to-do-sortas-alphabetical-odder-within-a-for-loop-as-expected-below-in-xsl