From cc1ac87c9913ca4df29bc3fe07ae80e32dbac401 Mon Sep 17 00:00:00 2001 From: James Dunkerley Date: Mon, 15 Jul 2024 19:33:37 +0100 Subject: [PATCH] Linting, XML to_table and fix JSON viz for XML (#10554) - Linting fixes. - `XML_Document` and `XML_Element` have `to_table` method. - Add `to_default_visualization_data` to `XML_Document` and `XML_Element`. - Add support to Table viz to render. ![image](https://github.com/user-attachments/assets/f01a3508-443e-48db-ad4f-605094a04c2b) ![image](https://github.com/user-attachments/assets/c7573b68-7549-494f-9c59-ea240178c0eb) --- .../Standard/Base/0.0.0-dev/src/Data/Map.enso | 2 ++ .../0.0.0-dev/src/Data/Text/Extensions.enso | 2 +- .../0.0.0-dev/src/Data/Time/Date_Time.enso | 2 +- .../Standard/Base/0.0.0-dev/src/Data/XML.enso | 33 ++++++++++++++++++- .../Standard/Table/0.0.0-dev/src/Column.enso | 2 +- .../src/Extensions/Table_Conversions.enso | 14 ++++++++ .../0.0.0-dev/src/Table/Visualization.enso | 27 +++++++++++++-- .../src/In_Memory/Table_Conversion_Spec.enso | 13 ++++++++ 8 files changed, 89 insertions(+), 6 deletions(-) diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso index f6508fc67a..d234710da4 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Map.enso @@ -21,6 +21,7 @@ type Map key value Error.throw (Deprecated.Warning "Standard.Base.Data.Map.Map" "singleton" "Deprecated: `Map.singleton` has been replaced by `Dictionary.singleton`.") ## PRIVATE + GROUP Constants ICON convert DEPRECATED Use Dictionary.from_keys_and_values instead. from_keys_and_values : Vector Any -> Vector Any -> Boolean -> Any ! Deprecated @@ -29,6 +30,7 @@ type Map key value Error.throw (Deprecated.Warning "Standard.Base.Data.Map.Map" "from_keys_and_values" "Deprecated: `Map.from_keys_and_values` has been replaced by `Dictionary.from_keys_and_values`.") ## PRIVATE + GROUP Constants ICON convert DEPRECATED Use Dictionary.from_vector instead. from_vector : Vector Any -> Boolean -> Any ! Deprecated diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso index 6fa86156f2..deb50a61fc 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Text/Extensions.enso @@ -1103,7 +1103,7 @@ Text.take self range:(Text_Sub_Range | Index_Sub_Range | Range | Integer)=..Firs "Hello World!".drop (..By_Index [Range 0 3, 6, Range 6 12 2]) == "lo ol!" "Hello World!".drop (..Sample 3 seed=42) == "HeloWorl!" @range Text_Sub_Range.default_widget -Text.drop : (Text_Sub_Range | Index_Sub_Range | Range) -> Text ! Index_Out_Of_Bounds +Text.drop : (Text_Sub_Range | Index_Sub_Range | Range | Integer) -> Text ! Index_Out_Of_Bounds Text.drop self range:(Text_Sub_Range | Index_Sub_Range | Range | Integer)=..First = ranges = Codepoint_Ranges.resolve self range case ranges of diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Date_Time.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Date_Time.enso index fce4ede75b..556c6e6b51 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Date_Time.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/Time/Date_Time.enso @@ -24,8 +24,8 @@ import project.Nothing.Nothing import project.Panic.Panic import project.Warning.Warning from project.Data.Boolean import Boolean, False, True -from project.Data.Time.Date import make_day_picker from project.Data.Text.Extensions import all +from project.Data.Time.Date import make_day_picker from project.Metadata import Display, Widget from project.Widget_Helpers import make_date_time_format_selector diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/XML.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/XML.enso index cea7a99f7d..b9cd0deb22 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Data/XML.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Data/XML.enso @@ -369,6 +369,16 @@ type XML_Document to_display_text : Text to_display_text self = "XML_Document (" + self.root_element.to_display_text + ")" + ## PRIVATE + Transform the XML document into text for displaying as part of its + default visualization. + to_default_visualization_data : Text + to_default_visualization_data self = + outer_vec = Vector.build initial_capacity=2 builder-> + builder.append ["type", "XML_Document"] + builder.append ["root_element", self.root_element.to_default_visualization_data as_js_object=True] + JS_Object.from_pairs outer_vec . to_json + type XML_Element ## GROUP Metadata ICON metadata @@ -673,7 +683,28 @@ type XML_Element new java_element = XML_Element.Value java_element (build_child_list java_element) ## PRIVATE - Value (java_element:Element) (~children_cache:(Vector (XML_Element | Text))) + private Value (java_element:Element) (~children_cache:(Vector (XML_Element | Text))) + + ## PRIVATE + Transform the vector into text for displaying as part of its default + visualization. + to_default_visualization_data : Boolean -> Boolean -> Text | JS_Object + to_default_visualization_data self nested:Boolean=False as_js_object:Boolean=False = + vec = Vector.build initial_capacity=4 builder-> + builder.append ["type", "XML_Element"] + builder.append ["tag", self.name] + if self.attributes.length > 0 then builder.append ["attributes", self.attributes.to_js_object] + if self.children_cache.length > 0 then + inner_render = if nested then _.to_display_text else + c-> case c of + _ : XML_Element -> c.to_default_visualization_data nested=True as_js_object=True + _ -> c + + ## Limit to 50 children to avoid excessive rendering. + builder.append ["children", self.children_cache.take 50 . map inner_render + (if self.children_cache.length > 50 then ["..."] else [])] + builder.append ["children_count", self.children_cache.length] + js_object = JS_Object.from_pairs vec + if as_js_object then js_object else js_object.to_json type XML_Error ## An error that indicates that the XML data could not be parsed. diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso index d0e45f6fc2..0398030aa6 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Column.enso @@ -10,8 +10,8 @@ import Standard.Base.Errors.Illegal_Argument.Illegal_Argument import Standard.Base.Errors.Illegal_State.Illegal_State import Standard.Base.Internal.Polyglot_Helpers import Standard.Base.Internal.Rounding_Helpers -from Standard.Base.Metadata.Widget import Numeric_Input from Standard.Base.Data.Index_Sub_Range import drop_helper, normalize_ranges, take_helper +from Standard.Base.Metadata.Widget import Numeric_Input from Standard.Base.Widget_Helpers import make_data_cleanse_vector_selector, make_format_chooser, make_regex_text_widget import project.Constants.Previous_Value diff --git a/distribution/lib/Standard/Table/0.0.0-dev/src/Extensions/Table_Conversions.enso b/distribution/lib/Standard/Table/0.0.0-dev/src/Extensions/Table_Conversions.enso index aa5f7e0f79..af6eceb4c6 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/src/Extensions/Table_Conversions.enso +++ b/distribution/lib/Standard/Table/0.0.0-dev/src/Extensions/Table_Conversions.enso @@ -57,6 +57,20 @@ JS_Object.to_table : Vector | Nothing -> Table ! Type_Error JS_Object.to_table self fields=Nothing = self.to Table fields +## GROUP Standard.Base.Conversions + ICON convert + Converts this `XML_Document` into a `Table`. +XML_Document.to_table : Table ! Type_Error +XML_Document.to_table self = + self.to Table + +## GROUP Standard.Base.Conversions + ICON convert + Converts this `XML_Document` into a `Table`. +XML_Element.to_table : Table ! Type_Error +XML_Element.to_table self = + self.to Table + ## GROUP Standard.Base.Constants ICON data_input Converts an object or a Vector of object into a Table, by looking up the diff --git a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso index 0e82180fc9..bb19b440b8 100644 --- a/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso +++ b/distribution/lib/Standard/Visualization/0.0.0-dev/src/Table/Visualization.enso @@ -49,8 +49,9 @@ prepare_visualization y max_rows=1000 = _ : Excel_Workbook -> js_value = x.to_js_object JS_Object.from_pairs [["json", js_value], ["sheet_names", x . sheet_names], ["type", "Excel_Workbook"]] - _ -> - make_json_for_other x + _ : XML_Document -> make_json_for_xml_element x.root_element max_rows "XML_Document" + _ : XML_Element -> make_json_for_xml_element x max_rows + _ -> make_json_for_other x result.to_text @@ -137,6 +138,28 @@ make_json_for_js_object js_object max_items = data = ["data", [mapped.map .first, mapped.map .second]] JS_Object.from_pairs [header, data, all_rows, ["type", "Map"]] +## PRIVATE + Render XML_Element to JSON +make_json_for_xml_element : XML_Element -> Integer -> Text -> JS_Object +make_json_for_xml_element xml_element max_items type:Text="XML_Element" = + header = ["header", ["key", "type", "value"]] + all_rows = ["all_rows_count", xml_element.attributes.length + xml_element.children.length] + + attribs = xml_element.attributes.to_vector.take max_items . map a-> ["@" + a.first, "Attribute", a.second] + children = xml_element.children.take (max_items - attribs.length) . map_with_index i->c-> if c.is_a Text then [i.to_text, "Text", c] else + render_start = "<"+c.name + render_attribs = if c.attributes.length == 0 then "" else + " " + ((c.attributes.to_vector.take 5 . map a-> a.first+'="'+a.second+'"') . join " ") + (if c.attributes.length > 5 then " ..." else "") + render_end = case c.child_count of + 0 -> "/>" + 1 -> if c.children.first.is_a Text then ">" + c.children.first + "" else "> ... 1 child element ... " + _ -> ">..." + c.child_count.to_text + " child elements..." + [i.to_text, "Element", render_start+render_attribs+render_end] + map_vector = Warning.clear (attribs + children) + + data = ["data", [map_vector.map .first, map_vector.map .second, map_vector.map i-> i.at 2]] + JS_Object.from_pairs [header, data, all_rows, ["type", type]] + ## PRIVATE Creates a JSON representation for the visualizations. diff --git a/test/Table_Tests/src/In_Memory/Table_Conversion_Spec.enso b/test/Table_Tests/src/In_Memory/Table_Conversion_Spec.enso index e49452f415..ddf4ae5a6b 100644 --- a/test/Table_Tests/src/In_Memory/Table_Conversion_Spec.enso +++ b/test/Table_Tests/src/In_Memory/Table_Conversion_Spec.enso @@ -399,6 +399,19 @@ add_specs suite_builder = t.at "Children" . at 0 . at 4 . name . should_equal "Magazine" t.column_names . should_not_contain "Value" + group_builder.specify "Can convert XML_Document and XML_Element to a table using to_table" <| + [data.library_document, data.library_root].map x-> + t = x.to_table + t.at "Name" . to_vector . should_equal ["Library"] + t.at "@catalog" . to_vector . should_equal ["Fiction"] + t.at "@letter" . to_vector . should_equal ["A"] + t.at "Children" . at 0 . at 0 . trim . should_equal "Hello" + t.at "Children" . at 0 . at 1 . name . should_equal "Book" + t.at "Children" . at 0 . at 2 . trim . should_equal "World" + t.at "Children" . at 0 . at 3 . name . should_equal "Book" + t.at "Children" . at 0 . at 4 . name . should_equal "Magazine" + t.column_names . should_not_contain "Value" + group_builder.specify "Can expand the Children column to rows" <| t = data.library_root.to Table . expand_to_rows "Children" t.at "Name" . to_vector . should_equal (Vector.fill 5 "Library")