How to loop through common id values in XSLT - xslt

I recently started working on XSLT. I have a requirement of grouping node values based on id field. However id field could be a duplicate value. For example, lets say below is the XML structure.
<ProductResults>
<ProductResult>
<ProductId>1000</ProductId>
<Location>Bangalore</Location>
<ModuleNumber>02</ModuleNumber>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>2000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Bangalore</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>01</ModuleNumber>
<Location>Mumbai</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>4000</ProductId>
<ModuleNumber>02</ModuleNumber>
<Location>Kolkata</Location>
<StoreId>1234<StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Chennai</Location>
<StoreId>1234<StoreId>
</ProductResult>
</ProductResults>
If you notice, the ProductId 1000 is repeating thrice. I am supposed to write XSLT to produce below output.
{
"StoreId": "1234",
"Locations": [
{
"ProductId": "1000",
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "02"
},
{
"Location": "Mumbai",
"ModuleNumber": "01"
},
{
"Location": "Chennai",
"ModuleNumber": "03"
}
]
},
{
"ProductId": "2000",
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "03"
}
]
},
{
"ProductId": "4000",
"Locations": [
{
"Location": "Kolkata",
"ModuleNumber": "02"
}
]
}
]
}
Since the ProductId field is repeating, I cannot use foreach loop directly which creates extra code block for same ProductId . Any suggestions on this?.
Thanks in advance.

The following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"
version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:apply-templates select="#*|node()" />
</xsl:template>
<xsl:template match="#*|node()">
<xsl:variable name="uniqueProducts"
select="count(//ProductId[not(. = following::ProductId)])"/>
{
"StoreId": <xsl:value-of select="ProductResult/StoreId"/>,
"Locations": [
<xsl:for-each select="//ProductId[not(. = following::ProductId)]">
<xsl:sort select="."/>
{
"ProductId": "<xsl:value-of select="."/>,
"Locations": [
<xsl:call-template name="location">
<xsl:with-param name="productId" select="."/>
</xsl:call-template>
]
<xsl:if test="position() < $uniqueProducts">,</xsl:if>
</xsl:for-each>
]}
</xsl:template>
<xsl:template name="location">
<xsl:param name="productId"/>
<xsl:for-each select="//ProductResult[ProductId=$productId]">
{
"Location": "<xsl:value-of select="Location"/>",
"ModuleNumber": "<xsl:value-of select="ModuleNumber"/>"
}
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied to the following (corrected, as you didn't close the StoreId in your example)
Input XML:
<ProductResults>
<ProductResult>
<ProductId>1000</ProductId>
<Location>Bangalore</Location>
<ModuleNumber>02</ModuleNumber>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>2000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Bangalore</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>01</ModuleNumber>
<Location>Mumbai</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>4000</ProductId>
<ModuleNumber>02</ModuleNumber>
<Location>Kolkata</Location>
<StoreId>1234</StoreId>
</ProductResult>
<ProductResult>
<ProductId>1000</ProductId>
<ModuleNumber>03</ModuleNumber>
<Location>Chennai</Location>
<StoreId>1234</StoreId>
</ProductResult>
</ProductResults>
produces the following
Output XML:
{
"StoreId": 1234,
"Locations": [
{
"ProductId": "1000,
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "02"
}
,
{
"Location": "Mumbai",
"ModuleNumber": "01"
}
,
{
"Location": "Chennai",
"ModuleNumber": "03"
}
]
,
{
"ProductId": "2000,
"Locations": [
{
"Location": "Bangalore",
"ModuleNumber": "03"
}
]
,
{
"ProductId": "4000,
"Locations": [
{
"Location": "Kolkata",
"ModuleNumber": "02"
}
]
]}
Note that this is only an example for the grouping, with e.g. an additional for-each loop it would be possible to adjust this to take care for more than a single StoreId.
For simplification I've just wrote this for the one StoreId provided using <xsl:value-of select="ProductResult/StoreId"/> instead of checking for different StoreId values and processing all of them.
For detailed references you can check this article by Jeni Tennison http://www.jenitennison.com/xslt/grouping/muenchian.xml for Muenchian Grouping, and
you can e.g. have a look at http://www.dpawson.co.uk/xsl/sect2/N4486.html for XSLT Grouping.
Update: Just adjusted first posted XSLT, and for explanation how this works - the <xsl:for-each select="//ProductId[not(. = following::ProductId)]"> loop processes all unique ProductId values, calling the <xsl:template name="location"> with the current ProductId as parameter and generating the output for every location that matches the ProductId. Though the updated approach doesn't use Muenchian Grouping, it may still be of value for you so I'll keep the reference.

Related

how to loop through current-group in xslt3.0 and print each value

I have a input json in the format
[
{
"PERSON_ID": 78,
"EFFECTIVE_START_DATE": "2013-12-02 00:00:00",
"LAST_NAME": "Hulk78"
},
{
"PERSON_ID": 78,
"EFFECTIVE_START_DATE": "2020-06-24 07:29:26",
"LAST_NAME": "Hulks78"
},
{
"PERSON_ID": 79,
"EFFECTIVE_START_DATE": "2015-12-02 00:00:00",
"LAST_NAME": "Hulk79"
},
{
"PERSON_ID": 79,
"EFFECTIVE_START_DATE": "2020-07-24 07:29:26",
"LAST_NAME": "Hulks79"
},
{
"PERSON_ID": 80,
"EFFECTIVE_START_DATE": "2013-12-10 00:00:00",
"LAST_NAME": "Hulk15"
}
]
The expected output
[
{
"PersonId": 78,
"value": [
{
"EffectiveDate": "2013-12-02 00:00:00",
"lastName":"Hulk78"
},
{
"EffectiveDate": "2020-06-24 07:29:26",
"lastName":"Hulks78"
}
]
}
....
]
I want to transform the input json by grouping the person_id value and for each group add its respective effectiveDate and lastname in a array of values corresponding to that person id.
Below is the xslt that i have tried.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0"
xmlns="http://www.w3.org/2005/xpath-functions" xpath-default-namespace="http://www.w3.org/2005/xpath-functions" expand-text="yes">
<xsl:param name="input"/>
<xsl:output method="text"/>
<xsl:template name="xsl:initial-template">
<xsl:variable name="input-as-xml" select="json-to-xml($input)"/>
<xsl:variable name="transformed-xml" as="element(array)">
<array>
<xsl:for-each-group select="$input-as-xml" group-by="//number[#key='PERSON_ID']">
<map>
<string key="PersonId">
<xsl:value-of select="current-grouping-key()"/>
</string>
<array key="Value">
<xsl:for-each select="current-group()">
<map>
<string key="EffectiveDate">
<xsl:value-of select="../string[#key='EFFECTIVE_START_DATE']"/>
</string>
<string key="LASTNAME">
<xsl:value-of select="#LAST_NAME"/>
</string>
</map>
</xsl:for-each>
</array>
</map>
</xsl:for-each-group>
</array>
</xsl:variable>
<xsl:value-of select="xml-to-json($transformed-xml)"/>
</xsl:template>
</xsl:stylesheet>
Can anyone please help me in understanding how to take out each effective date and last name from the current group.
This is the output i am getting
[
{
"PersonId": "78",
"Value": [
{
"EffectiveDate": "",
"LASTNAME": ""
}
]
},
{
"PersonId": "79",
"Value": [
{
"EffectiveDate": "",
"LASTNAME": ""
}
]
},
{
"PersonId": "80",
"Value": [
{
"EffectiveDate": "",
"LASTNAME": ""
}
]
}
]
You were close. This is how to build the variable:
<xsl:variable name="transformed-xml" as="element()">
<array>
<xsl:for-each-group select="$input-as-xml/array/map" group-by="number[#key='PERSON_ID']">
<map>
<string key="PersonId">
<xsl:value-of select="current-grouping-key()"/>
</string>
<array key="Value">
<xsl:for-each select="current-group()">
<map>
<string key="EffectiveDate">
<xsl:value-of select="string[#key='EFFECTIVE_START_DATE']"/>
</string>
<string key="LASTNAME">
<xsl:value-of select="string[#key='LAST_NAME']"/>
</string>
</map>
</xsl:for-each>
</array>
</map>
</xsl:for-each-group>
</array>
</xsl:variable>
Note that, as an alternative approach, you can also transform the JSON directly as XDM 3.1 maps and arrays and do the grouping on that data, without the need to convert to XML back and forth; the only drawback is that XSLT 3 lacks an instruction to create an array so there you have to rely on XPath 3.1 expressions like [ ] or array { } which sometimes requires you to use a function call inside a template.
An example for your sample would be
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:function name="mf:group" as="map(*)*">
<xsl:param name="persons" as="map(*)*"/>
<xsl:for-each-group select="$persons" group-by="?PERSON_ID">
<xsl:sequence select="map { 'PersonId' : current-grouping-key(),
'value' : array {
current-group() ! map { 'EffectiveDate ' : ?EFFECTIVE_START_DATE,
'lastName' : ?LAST_NAME } } }"/>
</xsl:for-each-group>
</xsl:function>
<xsl:output method="json" indent="yes"/>
<xsl:param name="json-input" as="xs:string"/>
<xsl:template name="xsl:initial-template">
<xsl:apply-templates select="parse-json($json-input)"/>
</xsl:template>
<xsl:template match=".">
<xsl:sequence select="array { mf:group(?*) }"/>
</xsl:template>
</xsl:stylesheet>
Another disadvantage to the JSON -> XML -> JSON conversion is the lack of order of the key value pairs in XDM maps, that way the serialized JSON often doesn't have the order of keys you expect. The commercial versions of Saxon have some extension attribute to define the order for serialization.
With xslt3 of Saxon JS 2.2 and later you can even feed the JSON directly as the input to the transform with the -json:data.json option and use e.g.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:function name="mf:group" as="map(*)*">
<xsl:param name="persons" as="map(*)*"/>
<xsl:for-each-group select="$persons" group-by="?PERSON_ID">
<xsl:sequence select="map { 'PersonId' : current-grouping-key(),
'value' : array {
current-group() ! map { 'EffectiveDate ' : ?EFFECTIVE_START_DATE,
'lastName' : ?LAST_NAME } } }"/>
</xsl:for-each-group>
</xsl:function>
<xsl:output method="json" indent="yes"/>
<xsl:template match=".">
<xsl:sequence select="array { mf:group(?*) }"/>
</xsl:template>
</xsl:stylesheet>
I think we will see a similar option for the next mayor Saxon Java release.

select and combine 2 arrays in xslt

I have a Input json below
[
{
"fileName": "abc",
"value": [
{
"SSC": {
"Payload": [
{
"Ledger": [
{
"Line": [
{
"AccountingCode": [
"402050046767"
],
"AccountingPeriod": [
"00720201243"
]
},
{
"AccountingCode": [
"203010334567"
],
"AccountingPeriod": [
"00720201234"
]
}
]
}
]
}
]
}
}
]
},
{
"fileName": "abc",
"value": [
{
"SSC": {
"Payload": [
{
"Ledger": [
{
"Line": [
{
"AccountingCode": [
"40205004"
],
"AccountingPeriod": [
"0072020"
]
},
{
"AccountingCode": [
"20301033"
],
"AccountingPeriod": [
"0072020"
]
}
]
}
]
}
]
}
}
]
}
]
my expected output is
[
{
"fileName": "abc",
"value": [
{
"SSC": {
"Payload": [
{
"Ledger": [
{
"Line": [
{
"AccountingCode": [
"402050046767"
],
"AccountingPeriod": [
"00720201243"
]
},
{
"AccountingCode": [
"203010334567"
],
"AccountingPeriod": [
"00720201234"
]
},
{
"AccountingCode": [
"40205004"
],
"AccountingPeriod": [
"0072020"
]
},
{
"AccountingCode": [
"20301033"
],
"AccountingPeriod": [
"0072020"
]
}
]
}
]
}
]
}
}
]
}
]
Below is the xslt i have tried but not getting the proper output
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="3.0"
xmlns="http://www.w3.org/2005/xpath-functions"
xpath-default-namespace="http://www.w3.org/2005/xpath-functions"
expand-text="yes">
<xsl:param name="input"/>
<xsl:output method="text"/>
<xsl:template name="xsl:initial-template">
<xsl:variable name="input-as-xml" select="json-to-xml($input)"/>
<xsl:variable name="transformed-xml" as="element(array)">
<array>
<map>
<string key="fileNames">
<xsl:for-each select="$input-as-xml//string[#key='fileName']">
<xsl:variable name="file" select="../string[#key='fileName']"/>
<xsl:value-of select="$file"/>
</xsl:for-each>
</string>
<array key="value">
<map>
<array key="SSC">
<map>
<array key="Payload">
<map>
<array key="Ledger">
<xsl:for-each select="$input-as-xml//array[#key='Ledger']">
<map>
<xsl:choose>
<xsl:when test="$input-as-xml//string[#key='fileName'] = 'abc'">
<xsl:value-of select="$input-as-xml//array[#key='Lines']"/>
</xsl:when>
</xsl:choose>
</map>
</xsl:for-each>
</array>
</map>
</array>
</map>
</array>
</map>
</array>
</map>
</array>
</xsl:variable>
<xsl:value-of select="xml-to-json($transformed-xml)"/>
</xsl:template>
</xsl:stylesheet>
I am tring to select Array "Lines" from the json if the file name is abc then combine the value of the selected in Array "Ledger"
Please can anyone help me understand how to achieve this in xslt.
You could do this without converting to XML and back again: just manipulate the JSON as a structure of maps and arrays. Something along the lines of
<xsl:template name="xsl:initial-template">
<xsl:variable name="in" select="json-doc('input.json')"/>
<xsl:variable name="out" as="map(*)*">
<xsl:for-each-group select="$in?*" group-by="?fileName">
<xsl:map>
<xsl:map-entry key="'fileName'" select="current-grouping-key()"/>
<xsl:map-entry key="'value'" select="
array {
map {'SSC':
map {'Payload':
array {
map {'Ledger':
array {
map{'Line': array:join(current-group()?
value?*?SSC?Payload?*?Ledger?*?Line)}
}
}
}
}"/>
</xsl:map>
</xsl:for-each-group>
</xsl:variable>
<xsl:sequence select="array{$out}"/>
</xsl:template>
I haven't tested this and there are probably a few bugs in the complex path to iron out, but I hope it conveys the idea.
(Note, this would be easier if XSLT 3.0 had an xsl:array instruction. If you're prepared to use Saxon extensions, there's a saxon:array that plugs this gap.)

Forced Alignment using google speech-to-text API?

I'm working with some recorded audio files and I do have the transcript of what's being said. The problem is that I'm working with Arabic(Egyptian) language, so the accuracy is not so great. What I need to do is to give the api the transcript containing the correct text and then forcibly align the speech to the text. In other words, get the timestamps of each word in the text in the speech.
So is there a way to do that?
The speech-to-Text is based in Machine learning algorithms, the training depends of the amount of data which those algorithms are feed; therefore, some languages could have better accuracy than others, if you are using Arabic you should try tweaking the parameters of the API
In addition, if you want to acquire the Timestamps, the API has an option for getting word timestamps, you can enable the "enableWordTimeOffsets" parameter in the request configuration, this parameter will return the "startTime" and the "endTime" of every word along with the whole transcript, the API will return a response like the follow:
{
"name": "7612202767953098924",
"metadata": {
"#type": "type.googleapis.com/google.cloud.speech.v1.LongRunningRecognizeMetadata",
"progressPercent": 100,
"startTime": "2017-07-20T16:36:55.033650Z",
"lastUpdateTime": "2017-07-20T16:37:17.158630Z"
},
"done": true,
"response": {
"#type": "type.googleapis.com/google.cloud.speech.v1.LongRunningRecognizeResponse",
"results": [
{
"alternatives": [
{
"transcript": "okay so what am I doing here...(etc)...",
"confidence": 0.96596134,
"words": [
{
"startTime": "1.400s",
"endTime": "1.800s",
"word": "okay"
},
{
"startTime": "1.800s",
"endTime": "2.300s",
"word": "so"
},
{
"startTime": "2.300s",
"endTime": "2.400s",
"word": "what"
},
{
"startTime": "2.400s",
"endTime": "2.600s",
"word": "am"
},
{
"startTime": "2.600s",
"endTime": "2.600s",
"word": "I"
},
{
"startTime": "2.600s",
"endTime": "2.700s",
"word": "doing"
},
{
"startTime": "2.700s",
"endTime": "3s",
"word": "here"
},
{
"startTime": "3s",
"endTime": "3.300s",
"word": "why"
},
{
"startTime": "3.300s",
"endTime": "3.400s",
"word": "am"
},
{
"startTime": "3.400s",
"endTime": "3.500s",
"word": "I"
},
{
"startTime": "3.500s",
"endTime": "3.500s",
"word": "here"
},
...
]
}
]
},
{
"alternatives": [
{
"transcript": "so so what am I doing here...(etc)...",
"confidence": 0.9642093,
}
]
}
]
}
}

How to use regex inside in query using morphia?

Mongodb allows regex expression of pattern /pattern/ without using $regex expression.
http://docs.mongodb.org/manual/reference/operator/query/in/
How can i do it using morphia ?
If i give Field criteria with field operator as in and value of type "java.util.regex.Pattern" then the equivalent query generated in
$in:[$regex: 'given pattern'] which wont return expected results at all.
Expectation: $in :[ /pattern1 here/,/pattern2 here/]
Actual using 'Pattern' object : $in : [$regex:/pattern1 here/,$regex:/pattern 2 here/]
I'm not entirely sure what to make of your code examples, but here's a working Morphia code snippet:
Pattern regexp = Pattern.compile("^" + email + "$", Pattern.CASE_INSENSITIVE);
mongoDatastore.find(EmployeeEntity.class).filter("email", regexp).get();
Note that this is really slow. It can't use an index and will always require a full collection scan, so avoid it at all cost!
Update: I've added a specific code example. The $in is not required to search inside an array. Simply use /^I/ as you would in string:
> db.profile.find()
{
"_id": ObjectId("54f3ac3fa63f282f56de64bd"),
"tags": [
"India",
"Australia",
"Indonesia"
]
}
{
"_id": ObjectId("54f3ac4da63f282f56de64be"),
"tags": [
"Island",
"Antigua"
]
}
{
"_id": ObjectId("54f3ac5ca63f282f56de64bf"),
"tags": [
"Spain",
"Mexico"
]
}
{
"_id": ObjectId("54f3ac6da63f282f56de64c0"),
"tags": [
"Israel"
]
}
{
"_id": ObjectId("54f3ad17a63f282f56de64c1"),
"tags": [
"Germany",
"Indonesia"
]
}
{
"_id": ObjectId("54f3ad56a63f282f56de64c2"),
"tags": [
"ireland"
]
}
> db.profile.find({ tags: /^I/ })
{
"_id": ObjectId("54f3ac3fa63f282f56de64bd"),
"tags": [
"India",
"Australia",
"Indonesia"
]
}
{
"_id": ObjectId("54f3ac4da63f282f56de64be"),
"tags": [
"Island",
"Antigua"
]
}
{
"_id": ObjectId("54f3ac6da63f282f56de64c0"),
"tags": [
"Israel"
]
}
{
"_id": ObjectId("54f3ad17a63f282f56de64c1"),
"tags": [
"Germany",
"Indonesia"
]
}
Note: The position in the array makes no difference, but the search is case sensitive. Use /^I/i if this is not desired or Pattern.CASE_INSENSITIVE in Java.
Single RegEx Filter
use .filter(), .criteria(), or .field()
query.filter("email", Pattern.compile("reg.*exp"));
// or
query.criteria("email").contains("reg.*exp");
// or
query.field("email").contains("reg.*exp");
Morphia converts this into:
find({"email": { $regex: "reg.*exp" } })
Multiple RegEx Filters
query.or(
query.criteria("email").contains("reg.*exp"),
query.criteria("email").contains("reg.*exp.*2"),
query.criteria("email").contains("reg.*exp.*3")
);
Morphia converts this into:
find({"$or" : [
{"email": {"$regex": "reg.*exp"}},
{"email": {"$regex": "reg.*exp.*2"}},
{"email": {"$regex": "reg.*exp.*3"}}
]
})
Unfortunately,
You cannot use $regex operator expressions inside an $in.
MongoDB Manual 3.4
Otherwise, we could do:
Pattern[] patterns = new Pattern[] {
Pattern.compile("reg.*exp"),
Pattern.compile("reg.*exp.*2"),
Pattern.compile("reg.*exp.*3"),
};
query.field().in(patterns);
hopefully, one day morphia will support that :)

CfChart Stacked bars and unstacked Lines

I am trying to create a CFChart with Stacked Bars and unstacked Lines. Have been trying to work around in the Webcharts Tool but no luck so far.
In the example image all the series are seriesplacement=stacked, but I want to have the bars(Avg and TDD) as stacked and the lines (Max and Min) as seriesplacement=default. Is there a way to achieve the same in Cfchart?
If I am understanding correctly, just set the placement of the line series in your xml style:
<?xml version="1.0" encoding="UTF-8"?>
<frameChart>
<elements place="Stacked" drawOutline="false">
<series index="0" place="Default" shape="Line" />
<series index="1" place="Default" shape="Line" />
</elements>
</frameChart>
Then generate a "stacked" chart as usual:
<cfchart format="png" style="#yourCustomStyle#">
<cfchartseries type="line" serieslabel="Min">
...
</cfchartseries>
<cfchartseries type="line" serieslabel="Max">
...
</cfchartseries>
<cfchartseries type="bar" serieslabel="Avg" >
...
</cfchartseries>
<cfchartseries type="bar" serieslabel="TDD">
...
</cfchartseries>
</cfchart>
CFChart is based on ZingCharts which is formatted using JSON. They have some good docs and a builder to develop with. I haven't figured out how to get the left y-scale to adjust to MIN value, MAX seems to be automatic. Below I put together some sample data and code (.cfm & .json) for you to get started with.
Some starter data and the CFChart info (Lines-StackedBars.cfm)
<cfscript>
GraphData = queryNew("");
queryAddColumn(GraphData, "dates", "Integer", ['1/1/11','1/2/11','1/3/11','1/4/11','1/5/11']);
queryAddColumn(GraphData, "MIN", "Integer", [42,37,45,29,61]);
queryAddColumn(GraphData, "MAX", "Integer", [110,98,82,103,94]);
queryAddColumn(GraphData, "AVG", "Integer", [80,75,80,65,85]);
queryAddColumn(GraphData, "TDD", "Integer", [23,33,32,28,26]);
</cfscript>
<cfchart chartwidth="800"
chartheight="500"
format="html"
style="LineStackedBar.json"
title="Unstacked Lines w/ Stacked Bars">
<cfchartseries query="GraphData"
type="Bar"
itemcolumn="dates"
valuecolumn="AVG"
color="blue"
serieslabel="AVG">
<cfchartseries query="GraphData"
type="Bar"
itemcolumn="dates"
valuecolumn="TDD"
color="green"
serieslabel="TDD">
<cfchartseries query="GraphData"
type="Line"
itemcolumn="dates"
valuecolumn="MIN"
color="red"
serieslabel="MIN">
<cfchartseries query="GraphData"
type="Line"
itemcolumn="dates"
valuecolumn="MAX"
color="orange"
serieslabel="MAX">
</cfchart>
The code above uses LineStackedBar.json to handle the formatting
{
"graphset":[
{
"legend":{
"position":"30%, 0%",
"border-color":"#CCCCCC",
"background-color":"#FFFFFF",
"margin-top":40,
"layout":"x4",
"shadow":false,
"alpha":1
},
"border-color":"#cccccc",
"tooltip":{
"font-size":11,
"font-color":"#FFFFFF",
"bold":true,
"font-family":"Helvetica",
"padding":5
},
"series":[
{
"hover-state":{
"visible":false
},
"shadow-blur-y":1,
"shadow-color":"#cccccc",
"shadow-alpha":1,
"shadow":true,
"background-color-2":"#FFCF8C",
"background-color":"#735328",
"type":"bar",
"stacked":"true",
"shadow-distance":2,
"shadow-blur-x":2
},
{
"hover-state":{
"visible":false
},
"shadow-blur-y":1,
"shadow-color":"#cccccc",
"shadow-alpha":1,
"shadow":true,
"background-color-2":"#FEFFD1",
"background-color":"#9D9C5D",
"type":"bar",
"stacked":"true",
"shadow-distance":2,
"shadow-blur-x":2
},
{
"hover-state":{
"visible":false
},
"line-color":"#699EBF",
"border-color":"#699EBF",
"line-width":3,
"type":"line",
"scales":"scale-x,scale-y-2",
"stacked":"false"
},
{
"hover-state":{
"visible":false
},
"line-color":"#143F59",
"border-color":"#143F59",
"line-width":3,
"type":"line",
"scales":"scale-x,scale-y-2",
"stacked":"false"
}
],
"scale-y":{
"tick":{
"line-gap-size":0,
"line-color":"#cccccc",
"line-width":1,
"size":10
},
"font-size":16,
"line-color":"#cccccc",
"bold":true,
"format":"%v",
"item":{
"font-size":11,
"font-family":"Helvetica",
"color":"#333333"
},
"label":{
"color":"#333333"
},
"line-width":2,
"font-family":"Helvetica",
"color":"#333333"
},
"scale-y-2":{
"tick":{
"line-gap-size":0,
"line-color":"#cccccc",
"line-width":1,
"size":10
},
"font-size":16,
"line-color":"#cccccc",
"bold":true,
"format":"%v",
"item":{
"font-size":11,
"font-family":"Helvetica",
"color":"#333333"
},
"label":{
"color":"#333333"
},
"line-width":2,
"font-family":"Helvetica",
"color":"#333333"
},
"plotarea":{
"margin-top":80,
"margin-left":70,
"margin-right":30
},
"scale-x":{
"tick":{
"line-gap-size":0,
"line-color":"#cccccc",
"line-width":1,
"size":10
},
"font-size":16,
"line-color":"#cccccc",
"bold":true,
"item":{
"font-size":11,
"font-family":"Helvetica",
"color":"#333333"
},
"guide":{
"line-width":0
},
"label":{
"color":"#333333"
},
"line-width":2,
"font-family":"Helvetica",
"color":"#333333"
},
"3d-aspect":{
"true3d":false
},
"background-color":"white",
"border-width":1,
"plot":{
"hover-marker":{
"background-color":"#888888",
"size":3
},
"marker":{
"background-color":"#cccccc",
"size":3
},
"preview":true,
"tooltip-text":"%v"
},
"type":"mixed",
"title":{
"border-width":1,
"border-color":"#cccccc",
"background-color":"white",
"font-size":18,
"bold":true,
"font-family":"Helvetica",
"color":"#333333"
}
}
]
}