Решил посмотреть, как может выглядеть более-менее универсальная функция...
Вот что получилось.
Код:
(VisioDocName,PropSection) =>
let
Source = File.Contents(VisioDocName),
Files = UnzipContents(Source),
Pages = Table.SelectRows(Files, each
Text.StartsWith([FileName], "visio/pages/page")
and not Text.EndsWith([FileName], "s.xml")),
ContentColumn = Table.AddColumn(Pages, "Custom", each Xml.Tables([Content])),
PageContents = Table.ExpandTableColumn(ContentColumn, "Custom", {"Table"}, {"Table"}),
ShapesTable = Table.ExpandTableColumn(PageContents, "Table", {"Table"}, {"Table.1"}),
ShapeTable = Table.ExpandTableColumn(ShapesTable, "Table.1", {"Section", "Attribute:ID"}, {"Section", "ShapeID"}),
ShapeFiltered = Table.SelectRows(ShapeTable, each ([#"ShapeID"] <> null)),
ExpandedSections = Table.ExpandTableColumn(ShapeFiltered, "Section", {"Row", "Attribute:N"}, {"Section.Row", "SectionName"}),
OneSectionOnly = Table.SelectRows(ExpandedSections, each ([#"SectionName"] = PropSection)),
ExpandedRows = Table.ExpandTableColumn(OneSectionOnly, "Section.Row", {"Cell", "Attribute:N"}, {"Section.Row.Cell", "PropRowName"}),
Row.Cells = Table.ExpandTableColumn(ExpandedRows, "Section.Row.Cell", {"Attribute:N", "Attribute:V"}, {"PropCellName", "PropVal"}),
ValueOnly = Table.SelectRows(Row.Cells, each ([#"PropCellName"] = "Value")),
RemovedCellName = Table.RemoveColumns(ValueOnly,{"PropCellName","Content"}),
PivotedProperty = Table.Pivot(RemovedCellName, List.Distinct(RemovedCellName[#"PropRowName"]), "PropRowName", "PropVal")
in
PivotedProperty
При вызове функции она принимает два параметра: полный путь к файлу Visio и имя секции, по которой нужно сделать отчет (например Property или User).
Возвращается табличка с ShapeID и найденными в соответствующей секции свойствами.
В принципе, пользователь может вообще ничего не знать о структуре XML Visio. Задействовал функцию - получил данные. Присутствие Visio на машине не требуется. В отчет собираются данные по всем страницам (в отличие от штатного формирователя отчетов, который работает только с одной страницей).
Обращаться можно, например, вот так:
Код:
let
Source = fShapePropFromAllPages("C:\Work\PowerQuery\Example\Doc1.vsdx","Property")
in
Source
То есть в принципе работать можно.
Теперь о впечатлениях... Так как Power Query попытался использовать первый раз, мороки было довольно много. Для парсинга XML он не приспособлен совершенно. Чтобы добраться до нужной таблицы приходится создавать целые цепочки последовательных преобразований. В целом программа получается громоздкая и практически нечитаемая. В общем, технология явно "на любителя".
И тем не менее, мысль о том, что нужно бы подумать над набором "типовых" функций, подобных представленной, не уходит
