#include "output/spv/spv-legacy-decoder.h"
#include "output/spv/spv-light-decoder.h"
#include "output/spv/structure-xml-parser.h"
+#include "output/spv/vizml-parser.h"
#include "gl/c-ctype.h"
#include "gl/intprops.h"
return item->type == SPV_ITEM_TABLE;
}
+bool
+spv_item_is_graph (const struct spv_item *item)
+{
+ return item->type == SPV_ITEM_GRAPH;
+}
+
bool
spv_item_is_text (const struct spv_item *item)
{
{
if (spv_item_is_table (item))
spv_item_get_table (item);
+ else if (spv_item_is_graph (item))
+ spv_item_get_graph (item);
}
bool
spv_item_get_raw_legacy_data (const struct spv_item *item,
void **data, size_t *size)
{
- if (!spv_item_is_legacy_table (item))
- return xstrdup ("not a legacy table object");
+ if (!spv_item_is_legacy_table (item) && !spv_item_is_graph (item))
+ return xstrdup ("not a graph or legacy table object");
+
+ if (!item->bin_member)
+ return xstrdup ("graph or legacy table lacks legacy data");
return zip_member_read_all (item->spv->zip, item->bin_member, data, size);
}
return item->table;
}
+static char * WARN_UNUSED_RESULT
+spv_open_graph (struct spv_item *item)
+{
+ assert (spv_item_is_graph (item));
+
+ struct spv_data data;
+ char *error = spv_item_get_legacy_data (item, &data);
+ if (error)
+ {
+ struct string s = DS_EMPTY_INITIALIZER;
+ spv_item_format_path (item, &s);
+ ds_put_format (&s, " (%s): %s", item->bin_member, error);
+
+ free (error);
+ return ds_steal_cstr (&s);
+ }
+
+ xmlDoc *doc;
+ error = spv_read_xml_member (item->spv, item->xml_member, false,
+ "visualization", &doc);
+ if (error)
+ {
+ spv_data_uninit (&data);
+ return error;
+ }
+
+ struct spvxml_context ctx = SPVXML_CONTEXT_INIT (ctx);
+ struct vizml_visualization *v;
+ vizml_parse_visualization (&ctx, xmlDocGetRootElement (doc), &v);
+ error = spvxml_context_finish (&ctx, &v->node_);
+
+ if (error)
+ {
+ struct string s = DS_EMPTY_INITIALIZER;
+ spv_item_format_path (item, &s);
+ ds_put_format (&s, " (%s): %s", item->xml_member, error);
+
+ free (error);
+ error = ds_steal_cstr (&s);
+ }
+
+ spv_data_uninit (&data);
+ vizml_free_visualization (v);
+ if (doc)
+ xmlFreeDoc (doc);
+
+ return error;
+}
+
+void
+spv_item_get_graph (const struct spv_item *item_)
+{
+ struct spv_item *item = CONST_CAST (struct spv_item *, item_);
+
+ assert (spv_item_is_graph (item));
+ if (!item->graph)
+ {
+ item->graph = true;
+ char *error = spv_open_graph (item);
+ if (error)
+ {
+ item->error = true;
+ msg (ME, "%s", error);
+ free (error);
+ }
+ }
+}
+
/* Constructs a new spv_item from XML and stores it in *ITEMP. Returns NULL if
successful, otherwise an error message for the caller to use and free (with
free()).
item->subtype = xstrdup_if_nonempty (table->sub_type);
if (ts->path)
{
- item->xml_member = ts->path ? xstrdup (ts->path->text) : NULL;
+ item->xml_member = xstrdup_if_nonempty (ts->path->text);
char *error = decode_spvsx_legacy_properties (
table->table_properties, &item->legacy_properties);
if (error)
}
else if (spvsx_is_graph (content))
{
- struct spvsx_graph *graph = spvsx_cast_graph (content);
item->type = SPV_ITEM_GRAPH;
+
+ struct spvsx_graph *graph = spvsx_cast_graph (content);
+ item->bin_member = xstrdup_if_nonempty (graph->data_path->text);
item->command_id = xstrdup_if_nonempty (graph->command_name);
- /* XXX */
+ item->xml_member = xstrdup_if_nonempty (graph->path->text);
}
else if (spvsx_is_model (content))
{
--- /dev/null
+# PSPP - a program for statistical analysis.
+# Copyright (C) 2017, 2018, 2019 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+visualization
+ :creator?
+ :date
+ :description
+ :lang
+ :name
+ :style[style_ref]=ref style
+ :type
+ :version
+ :schemaLocation?
+ :clip?
+=> location*
+ visualization_extension?
+ userSource
+ (sourceVariable | derivedVariable | expressionVariable)+
+ categoricalDomain?
+ intervalDomain*
+ graph
+ labelFrame[lf1]*
+ container?
+ labelFrame[lf2]*
+ style+
+ layerController?
+ styleCycle*
+ style[s2]*
+
+extension[visualization_extension]
+ :numRows=int?
+ :showGridline=bool?
+ :minWidthSet=(true)?
+ :maxWidthSet=(true)?
+ :legend1?
+ :legend2?
+ :styleCycleRepository?
+ :title1?
+ :title2?
+ :subtitle?
+ :footnote1?
+ :footnote2?
+ :footnote3?
+ :textbox1?
+ :textbox2?
+ :statisticsSummary?
+ :statisticsSummary1?
+ :dataSetHandle_0?
+ :dataSetName_0?
+ :dataSetHandle_1?
+ :dataSetName_1?
+ :dataSetHandle_2?
+ :dataSetName_2?
+ :percentDomain=(percentDomain)?
+ :regionStatistic_2270?
+ :regionStatistic_2737?
+ :smoothStatistic_2717?
+ :originLineY?
+ :boxplotLinkWidth=bool?
+=> EMPTY
+
+userSource :missing=(listwise | pairwise)? => EMPTY # Related to omit_empty?
+
+categoricalDomain => variableReference categories? simpleSort?
+
+intervalDomain
+ :date=bool?
+=> ETC
+
+categories
+ :remove=bool?
+=> ETC
+
+simpleSort
+ :method[sort_method]=(custom | natural)
+=> categoryOrder
+
+sourceVariable
+ :id
+ :categorical=bool
+ :source
+ :domain=ref categoricalDomain?
+ :sourceName
+ :dependsOn=ref sourceVariable?
+ :label?
+ :labelVariable=ref sourceVariable?
+ :creator?
+ :key=bool?
+ :weight=bool?
+ :shortLabel?
+ :description?
+=> variable_extension* (format | stringFormat)?
+
+derivedVariable
+ :id
+ :categorical=(true)
+ :value
+ :dependsOn=ref sourceVariable?
+ :creator?
+ :key=bool?
+ :label?
+ :source?
+ :weight=bool?
+=> variable_extension* (format | stringFormat)? valueMapEntry*
+
+extension[variable_extension]
+ :from?
+ :helpId?
+ :statistic?
+ :valuesAreGroupedMidpoints=bool?
+ :max?
+ :min?
+=> EMPTY
+
+expressionVariable
+ :categorical=bool?
+ :creator?
+ :expression?
+ :shortLabel?
+ :label?
+=> ETC
+
+valueMapEntry :from :to => EMPTY
+
+categoryOrder => TEXT
+
+graph
+ :cellStyle=ref style
+ :style=ref style
+ :axesOutside=bool?
+=> location+ coordinates faceting? point[p1]? facetLayout?
+ line[line1]? point[p2]? schema? interval* lineGuide? line[line2]?
+ functionGuide*
+
+location
+ :part=(height | width | top | bottom | left | right)
+ :method=(sizeToContent | attach | fixed | same)
+ :min?
+ :max?
+ :target=ref (labelFrame | graph | container)?
+ :value?
+ :specifiedByUser=bool?
+=> EMPTY
+
+coordinates
+=> (dimension | transposeTransform | reflectionTransform | polarTransform)*
+
+dimension
+ :domain?
+ :lowerMargin?
+ :upperMargin?
+ :niceLowerMapping=bool?
+ :niceUpperMapping=bool?
+ :unionDomain=bool?
+ :clusterGap?
+ :clusterVariable?
+=> ETC
+
+transposeTransform => ETC
+
+reflectionTransform
+ :alternating=bool?
+ :dimension?
+=> ETC
+
+polarTransform
+ :counterClockwise=bool?
+ :cycles=int?
+ :startAngle=real?
+=> ETC
+
+faceting
+ :method[faceting_method]=(nest | cross | dot)?
+=> layer[layers1]* cross layer[layers2]*
+
+cross => (unity | nest | cross | variableReference)+
+
+nest => variableReference[vars]+
+
+unity => EMPTY
+
+variableReference :ref=ref (sourceVariable | derivedVariable) => EMPTY
+
+layer
+ :variable=ref (sourceVariable | derivedVariable)
+ :value
+ :visible=bool?
+ :method[layer_method]=(nest)?
+ :titleVisible=bool?
+=> EMPTY
+
+facetLayout
+ :topDown=bool?
+ :method[facetLayout_method]=(structured)?
+ :cellAspect=int?
+=> tableLayout? setCellProperties[scp1]*
+ facetLevel* setCellProperties[scp2]*
+
+tableLayout
+ :verticalTitlesInCorner=bool
+ :style=ref style?
+ :fitCells=(ticks both)?
+=> EMPTY
+
+facetLevel
+ :level=int
+ :gap?
+=> axis?
+
+point
+ :dot=bool?
+ :name?
+ :showCollidingLabels=bool?
+ :labelCollisionHandling=(none | normal)?
+ :style=ref style?
+ :positionModifier=(none | stack)?
+ :zOrder=int?
+=> ETC
+
+line
+ :breakRepresentation?
+ :labelCollisionHandling=(none | normal)?
+ :showCollidingLabels=bool?
+ :name?
+ :style=ref style?
+ :dot=bool?
+ :positionModifier=(none | stack)?
+ :showDiscontinuity=bool?
+ :zOrder=int?
+ :coordinates?
+=> ETC
+
+lineGuide
+ :style=ref style?
+ :x=int?
+ :y=int?
+=> ETC
+
+functionGuide
+ :name
+ :segments=int?
+ :style=ref style?
+ :value?
+=> ETC
+
+schema
+ :dot=bool?
+ :extremeStyle?
+ :fenceStyle=ref style?
+ :hingeStyle=ref style?
+ :medianStyle=ref style?
+ :name?
+ :outlierStyle=ref style?
+ :showCollidingLabels=bool?
+ :labelCollisionHandling=(none | normal)?
+ :style=ref style?
+ :positionModifier=(none | stack)?
+ :zOrder=int?
+=> ETC
+
+axis
+ :style=ref style
+ :opposite=bool?
+ :repeat=(never)?
+=> label? majorTicks
+
+label
+ :style=ref style
+ :textFrameStyle=ref style?
+ :purpose=(title | subTitle | subSubTitle | layer | footnote)?
+=> text+ | descriptionGroup
+
+descriptionGroup
+ :target=ref (faceting | interval)
+ :separator?
+=> (description | text)+
+
+description
+ :name?
+=> format*
+
+majorTicks
+ :labelAngle=int
+ :length=dimension
+ :style=ref style
+ :tickFrameStyle=ref style
+ :labelFrequency=int?
+ :stagger=bool?
+ :markStyle=ref style?
+ :base=int?
+=> gridline?
+
+gridline
+ :style=ref style
+ :zOrder=int
+=> EMPTY
+
+setCellProperties
+ :applyToConverse=bool?
+=> (setStyle | setFrameStyle | setFormat | setMetaData)* union[union_]?
+
+setStyle
+ :target=ref (labeling | graph | interval | majorTicks)
+ :style=ref style
+=> EMPTY
+
+setMetaData
+ :target=ref graph
+ :key
+ :value
+=> EMPTY
+
+setFormat
+ :target=ref (majorTicks | labeling)
+ :reset=bool?
+=> format | numberFormat | stringFormat+ | dateTimeFormat | elapsedTimeFormat
+
+setFrameStyle
+ :style=ref style
+ :target=ref majorTicks
+=> EMPTY
+
+format
+ :baseFormat[f_base_format]=(date | time | dateTime | elapsedTime)?
+ :errorCharacter?
+ :separatorChars?
+ :mdyOrder=(dayMonthYear | monthDayYear | yearMonthDay)?
+ :showYear=bool?
+ :showQuarter=bool?
+ :quarterPrefix?
+ :quarterSuffix?
+ :yearAbbreviation=bool?
+ :showMonth=bool?
+ :monthFormat=(long | short | number | paddedNumber)?
+ :dayPadding=bool?
+ :dayOfMonthPadding=bool?
+ :showWeek=bool?
+ :weekPadding=bool?
+ :weekSuffix?
+ :showDayOfWeek=bool?
+ :dayOfWeekAbbreviation=bool?
+ :hourPadding=bool?
+ :minutePadding=bool?
+ :secondPadding=bool?
+ :showDay=bool?
+ :showHour=bool?
+ :showMinute=bool?
+ :showSecond=bool?
+ :showMillis=bool?
+ :dayType=(month | year)?
+ :hourFormat=(AMPM | AS_24 | AS_12)?
+ :minimumIntegerDigits=int?
+ :maximumFractionDigits=int?
+ :minimumFractionDigits?
+ :useGrouping=bool?
+ :scientific=(onlyForSmall | whenNeeded | true | false)?
+ :small=real?
+ :prefix?
+ :suffix?
+ :tryStringsAsNumbers=bool?
+ :negativesOutside=bool?
+ :hiddenseparator=bool?
+=> relabel* affix*
+
+numberFormat
+ :minimumIntegerDigits?
+ :maximumFractionDigits=int?
+ :minimumFractionDigits=int?
+ :useGrouping=bool?
+ :scientific=(onlyForSmall | whenNeeded | true | false)?
+ :small=real?
+ :prefix?
+ :suffix?
+=> affix*
+
+stringFormat => relabel* affix*
+
+dateTimeFormat
+ :baseFormat[dt_base_format]=(date | time | dateTime)
+ :separatorChars?
+ :mdyOrder=(dayMonthYear | monthDayYear | yearMonthDay)?
+ :showYear=bool?
+ :yearAbbreviation=bool?
+ :showQuarter=bool?
+ :quarterPrefix?
+ :quarterSuffix?
+ :showMonth=bool?
+ :monthFormat=(long | short | number | paddedNumber)?
+ :showWeek=bool?
+ :weekPadding=bool?
+ :weekSuffix?
+ :showDayOfWeek=bool?
+ :dayOfWeekAbbreviation=bool?
+ :dayPadding=bool?
+ :dayOfMonthPadding=bool?
+ :hourPadding=bool?
+ :minutePadding=bool?
+ :secondPadding=bool?
+ :showDay=bool?
+ :showHour=bool?
+ :showMinute=bool?
+ :showSecond=bool?
+ :showMillis=bool?
+ :dayType=(month | year)?
+ :hourFormat=(AMPM | AS_24 | AS_12)?
+=> affix*
+
+elapsedTimeFormat
+ :baseFormat[dt_base_format]=(date | time | dateTime)
+ :dayPadding=bool?
+ :hourPadding=bool?
+ :minutePadding=bool?
+ :secondPadding=bool?
+ :showYear=bool?
+ :showDay=bool?
+ :showHour=bool?
+ :showMinute=bool?
+ :showSecond=bool?
+ :showMillis=bool?
+=> affix*
+
+affix
+ :definesReference=int
+ :position=(subscript | superscript)
+ :suffix=bool
+ :value
+=> EMPTY
+
+relabel
+ :from
+ :to
+=> EMPTY
+
+union => intersect+
+
+intersect => where+ | intersectWhere | alternating | EMPTY
+
+where
+ :variable=ref (sourceVariable | derivedVariable)
+ :include
+=> EMPTY
+
+intersectWhere
+ :variable=ref (sourceVariable | derivedVariable)
+ :variable2=ref (sourceVariable | derivedVariable)
+=> EMPTY
+
+alternating => EMPTY
+
+text
+ :usesReference=int?
+ :definesReference=int?
+ :position=(subscript | superscript)?
+ :style=ref style
+=> TEXT
+
+interval
+ :style=ref style
+ :dot=bool?
+ :labelCollisionHandling=(none | normal)?
+ :showCollidingLabels=bool?
+ :name?
+ :positionModifier=(none | stack)?
+ :zOrder=int?
+=> binStatistic? summaryStatistic? styleBy? color? x? y? labeling? footnotes?
+
+labeling
+ :style=ref style?
+ :variable=ref (sourceVariable | derivedVariable)
+=> (formatting | format | footnotes)*
+
+formatting :variable=ref (sourceVariable | derivedVariable) => formatMapping*
+
+formatMapping :from=int => format?
+
+color
+ :affect=(both)?
+ :cycle=ref styleCycle?
+ :variable?
+ :clamp=bool?
+=> ETC
+
+x
+ :variable?
+=> ETC
+
+y
+ :variable?
+=> ETC
+
+styleBy
+ :styleCycle?
+ :variable?
+ :dimension=int?
+=> ETC
+
+binStatistic
+ :gridType=(square)?
+ :binWidth=real?
+ :binCount=int?
+=> ETC
+
+summaryStatistic
+ :method[summaryStatistic_method]=(count | range)?
+ :symbol[summaryStatistic_symbol]=(circle | square)?
+ :summaryBase=(coordinate)?
+ :convertIntervalToSingleValue=bool?
+=> ETC
+
+footnotes
+ :superscript=bool?
+ :variable=ref (sourceVariable | derivedVariable)
+=> footnoteMapping*
+
+footnoteMapping :definesReference=int :from=int :to => EMPTY
+
+style
+ :color=color?
+ :color2=color?
+ :labelAngle=real?
+ :border-bottom=(solid | thick | thin | double | none)?
+ :border-top=(solid | thick | thin | double | none)?
+ :border-left=(solid | thick | thin | double | none)?
+ :border-right=(solid | thick | thin | double | none)?
+ :border-bottom-color?
+ :border-top-color?
+ :border-left-color?
+ :border-right-color?
+ :font-family?
+ :font-size?
+ :font-weight=(regular | bold)?
+ :font-style=(regular | italic)?
+ :font-underline=(none | underline)?
+ :margin-bottom=dimension?
+ :margin-left=dimension?
+ :margin-right=dimension?
+ :margin-top=dimension?
+ :textAlignment=(left | right | center | decimal | mixed)?
+ :labelLocationHorizontal=(positive | negative | center)?
+ :labelLocationVertical=(positive | negative | center)?
+ :decimal-offset=dimension?
+ :size?
+ :width?
+ :visible=bool?
+ :pattern=int?
+ :stroke-linecap=(butt | round)?
+ :stroke-width=dimension?
+ :stroke-dasharray?
+ :text-fit=bool?
+ :depth?
+ :symbol=(circle | ibeam | flower)?
+ :margin=dimension?
+ :padding=dimension?
+=> style*
+
+layerController
+ :source=(tableData)
+ :target=ref label?
+=> EMPTY
+
+container
+ :style=ref style
+ :clip=bool?
+=> container_extension? location+ labelFrame* legend?
+
+extension[container_extension] :combinedFootnotes=(true) => EMPTY
+
+labelFrame :style=ref style => location+ label? paragraph?
+
+legend
+ :style=ref style?
+ :tickFrameStyle=ref style?
+ :tickTextStyle=ref style?
+=> ETC
+
+paragraph :hangingIndent=dimension? => EMPTY
+
+styleCycle
+=> ETC