Страницы: 1 2 След.
RSS
Выгрузка XML (сложная архитектура) в Excel средствами Power Query
 
Думал что имеющихся знаний достаточно, но тут попала задача обработать данные находящиеся в формате XML (со сложной архитектурой). Попробовал  в PowerQuery, почитал понял что не по силам. Решил снова обратиться за помощью.

Во вложении исходный "XML файл" (который пробую обработать и выгрузить в Excel) и "Файл1" (в котором указана структура данных в программе откуда производится выгрузка - StoreHause).

Буду снова признателен за помощь ("XML файл" - не хотел загружаться не смотря на небольшой вес - разместил его в архиве)
 
Покопавшись в архитектуре понял через какие поля Справочник группировки (Group) строк увязан со строками (Record), но вот как понять где и какой заголовок (видимо это Field) не могу пока.

Понимаю что стоит задача формирования строк, в привязке к группировке, к которой нужно разместить заголовки (ну или понять какие колонки что означают).

Обновил: вторую часть решил (сверив данные в XML и первоисточнике), завтра попробую решить первую часть - свести Record в таблицу.
Изменено: mitox - 03.04.2020 20:03:20
 
Ваш XML разворачивается в диапазон А1:CSZ10... Вы меня извините, но я не готов убить вечер пятницы на исследование его структуры. Сейчас настраиваю парсинг таможенных деклараций в формате XML - это еще то удовольствие.
Укажите, какие элементы вам нужно вытянуть.

upd. Еще имеет смысл в части "как надо" первую строку для примера целиком вам заполнить: я не вижу признаков, которые явно бы указывали, какое значение является количеством, какое НСП и т.п.
Изменено: genosser - 03.04.2020 20:17:26
 
Цитата
genosser написал: убить вечер пятницы на исследование его структуры
Извиняюсь. Осознаю. Частично разобрался со структурой - но завтра еще раз проверю и тогда уже отпишусь.

Цитата
genosser написал: как надо" первую строку для примера целиком вам заполнить
Это я уже нашел (перепроверить хочу - на текущий момент у видел что сумм нет, а есть цены и количество, вот и засомневался в корректности найденного). Но еще также нужно посмотреть на Группировку. И отпишусь.
 
genosser, Проверил.
Я сделал более простую выгрузку (архив "XML-файл") - с одним десятком строк (Record) и двумя группировками (Group).

Также приложил ("Файл4") где указал:
- наименования Колонок в Record необходимых для выгрузки
- двух колонок с суммами не нашел, но есть количество и цена, буду благодарен если автоматически по мимо количества и цены появится расчетная стоимость
- запись о дате содержится только в первой строке Record
- наименования колонок в Group по которым нужно подтянуть "Наименования" группировок которыми нужно заменить их коды в Record
- выложил скрин исходной таблицы

Еще раз спасибо. Мне в последствии предстоит выгрузить и переработать в базу данных четыре года по трем предприятиям.
Обновил - цены себестоимости и продажи почему то указаны умноженными на 10 000. Не указал это в файле. Их желательно сделать адекватными.
Изменено: mitox - 03.04.2020 22:09:00
 
Мне удалось собрать Record в таблицу (см."Файл 4_2") используя помощьпо аналогичной теме, но в процессе сборки я столкнулся с тем что вместо одной строки получил ее деление на несколько (см.скрин) и тут я стал уже использовать кнопки...

Может есть вариант проще?

P.S. Привязывать справочники Группировок я пока не стал. Также потерял дату и еще одну Группировку...

upd. Попробовал на выгрузке за месяц - там проблемы скрина не оказалось. Пробую дальше (вопрос снимаю).
Изменено: mitox - 04.04.2020 07:25:17
 
Такой вариант
Код
let
    Source = Table.FromColumns({Lines.FromBinary(File.Contents("C:\XML-файл\XML-файл.xml"))}),
    Records = Table.Skip(Table.Group(Source, {"Column1"}, {{"All", each _, type table}}, 0, (a,b)=> Number.From( Text.StartsWith(b[Column1], "      <Records>"))){1}[All],1),
    Records2 = List.RemoveLastN(Text.Split(Text.Combine(Table.FirstN(Table.Group(Records, {"Column1"}, {{"All", each _, type table}}, 0, (a,b)=> Number.From( Text.StartsWith(b[Column1], "      </Records>"))),1)[All]{0}[Column1]),"/>")),
    Records3 = Table.FromRows(List.Transform(Records2, each  Text.Split(_,"f")))
in
    Records3
 
Михаил Л, На строке 3 Пишет ошибку "Элементов в перечислении было недостаточно для выполнения операции."

upd На этапе удаления первой строки
Код
Table.Skip  ({1}[All],1) 
выдает "Не удается применить доступ к полям в типе List."
Изменено: mitox - 04.04.2020 08:20:03
 
mitox, мой запрос работает с файлом из #5. Наверное, надо только настроит отступы в "      <Records>"
Еще один шаг можно добавить в конце с формулой
Код
= Table.TransformColumns(Records3,List.Transform(List.Skip(Table.ColumnNames(Records3),1), each {_ , each Text.BetweenDelimiters(_, "=""", """")}))
Изменено: Михаил Л - 04.04.2020 08:33:04 (Добавил фал)
 
Михаил Л, Работает. Спасибо что заставляете подумать.

upd Не могу все эту строку разбить на две - пишет "Не удается применить доступ к полям в типе List."

Код
Records = Table.Skip(Table.Group(Source, {"Column1"}, {{"All", each _, type table}}, 0, (a,b)=> Number.From( Text.StartsWith(b[Column1], "      <Records>"))){1}[All],1),
Код
    Group = Table.Group(Source, {"Column1"}, {{"All", each _, type table}}, 0, (a,b)=> Number.From( Text.StartsWith(b[Column1], "      <Records>"))),
    Records = Table.Skip({1}[All],1),
Изменено: mitox - 04.04.2020 08:52:41
 
Код
= Table.Skip(Group{1}[All],1)
 
Михаил Л, Я так тоже пробовал - пишет "Элементов в перечислении было недостаточно для выполнения операции."
 
mitox, у меня работает
Код
let
    Source = Table.FromColumns({Lines.FromBinary(File.Contents("C:\abc\XML-файл\XML-файл.xml"))}),
    Group = Table.Group(Source, {"Column1"}, {{"All", each _, type table}}, 0, (a,b)=> Number.From( Text.StartsWith(b[Column1], "      <Records>"))),
    Custom2 = Table.Skip( Group{1}[All],1),
    Records2 = List.RemoveLastN(Text.Split(Text.Combine(Table.FirstN(Table.Group(Custom2, {"Column1"}, {{"All", each _, type table}}, 0, (a,b)=> Number.From( Text.StartsWith(b[Column1], "      </Records>"))),1)[All]{0}[Column1]),"/>")),
    Records3 = Table.FromRows(List.Transform(Records2, each  Text.Split(_,"f"))),
    Custom1 = Table.TransformColumns(Records3,List.Transform(List.Skip(Table.ColumnNames(Records3),1), each {_ , each Text.BetweenDelimiters(_, "=""", """")}))
in
    Custom1
 
Михаил Л,  Странно, у меня при таком разбиении - нет, выдает ту же ошибку (видимо особенности версии PQ).
 
Цитата
mitox написал:
при таком разбиении
То есть без разбиения запрос работает, а при разделении формулы перестает работать? Однако, странно
 
Код
let
    fnParentValuesRecursive = (src as table, ParentField as text, ChildField as text, ValueField as text) => let
        Inital  = Table.FromColumns({Table.Column(src,ChildField)},{"child"}),
        fn = (optional table as nullable table, optional depth as nullable number) => 
            let
                t = if table = null then Inital else table,
                d = if depth = null then 1 else depth,
                AddedColumn = Table.AddColumn(t, "x", each
                    let 
                        Child   = [child],
                        Filter  = Table.SelectRows(src,(r)=>Record.Field(r,ChildField)=Child),
                        Select  = Table.SelectColumns(Filter,{ValueField,ParentField}),
                        Renamed = Table.RenameColumns(Select,{{ValueField,"val"&Text.From(d)},{ParentField,"child"}}),
                        Dummy   = #table({"child","x"},{})
                    in if Table.RowCount(Filter)>0 then @fn(Renamed,d+1) else Dummy),
                DistinctColumns = List.Distinct(List.Combine(List.Transform(AddedColumn[x],Table.ColumnNames))),
                AllColumns      = if d>1  then Table.ColumnNames(AddedColumn[x]{0}) else DistinctColumns,
                NeededColumns   = List.Select(AllColumns,each Text.StartsWith(_,"val")),
                Expand          = Table.ExpandTableColumn(AddedColumn,"x",NeededColumns),
                Combine         = Table.CombineColumns(Expand,List.Reverse(NeededColumns),(a)=>Text.TrimStart(Text.Combine(List.RemoveNulls(a),"|"),{"|"}),"val")
            in Combine
    in Table.RenameColumns(fn(),{{"child",ChildField},{"val",ValueField}}),
    
    Source = Text.Replace(Text.Replace(Text.Replace(Text.FromBinary(File.Contents("C:\Users\Krosav4ig\Downloads\XML файл.xml")),"#(cr,lf)","\n"),"<","<"),">",">"),
    DataSet = Xml.Tables(Web.Page("<script>
                    document.write('<table><tr><th>xml</th></tr><tr><td>"&Source&"'
                        .replace(/(\<[frg])(\d+)/g,'$1 n=""$2""')
                        .replace(/(\<\/*[frg])\d+(\>)/g,'$1$2')+'</td></tr></table>')
              </script>"){0}[Data]{0}[xml]){1}[Table],
    Date = Date.From(Table.SelectRows(DataSet,each [Fields]{0}[f]{0}[#"Attribute:Id"]="_Rpt_Period_Object")[Records]{0}[r]{0}[#"Attribute:f21"]{0}),
    Groups = let
        a = Table.Combine(List.Transform(List.RemoveNulls(DataSet[Groups]),each _{0}[g]))[[DataSet],[#"Attribute:pKey"]],
        b = Table.ReplaceValue(a,null,null,(a,b,c)=>
                let 
                    rec=a{0}[Records]{0}[r] 
                in 
                    if a{0}[Fields]{0}[f]{[#"Attribute:Id"="_GrpTreePerent_"]}?=null 
                        then rec 
                        else fnParentValuesRecursive(Table.Buffer(rec),"Attribute:f2","Attribute:f0","Attribute:f1")
            ,{"DataSet"}),
        c = Table.ExpandTableColumn(Table.NestedJoin(b,"Attribute:pKey",DataSet{[#"Attribute:Id"="300"]}[Fields]{0}[f],"Attribute:Id","a"),"a",{"Attribute:n"}),
        d = Table.ExpandTableColumn(c, "DataSet", {"Attribute:f0", "Attribute:f1"})
    in d,
    Records = Table.SelectColumns(DataSet{[#"Attribute:Id"="300"]}[Records]{0}[r],List.Transform({1,2,9,18,19,34},each "Attribute:f"& Text.From(_))),
    Unpivot = Table.Unpivot(Records, {"Attribute:f18", "Attribute:f19"}, "Атрибут", "Значение"),
    Replace = Table.ReplaceValue(Unpivot,"Attribute:f","",Replacer.ReplaceText,{"Атрибут"}),
    Nested  = Table.NestedJoin(Replace,{"Атрибут","Значение"},Groups,{"Attribute:n","Attribute:f0"}," "),
    Expand  = Table.ExpandTableColumn(Table.RemoveColumns(Nested,{"Значение"}), " ", {"Attribute:f1"}, {"Значение"}),
    Pivot   = Table.Pivot(Expand, List.Distinct(Expand[Атрибут]), "Атрибут", "Значение"),
    Merge   = Table.CombineColumns(Pivot,{"Attribute:f1", "Attribute:f2", "Attribute:f9"},(a)=>
                  [ Количество=Number.From(a{2}),
                    Закупка=Number.From(a{0})/10000,
                    #"Сумма закупки"=Количество*Закупка,
                    Продажа=Number.From(a{1})/10000,
                    #"Сумма продажи"=Количество*Продажа,
                    Дата=Date ]
              ,"x"),
    Expand1 = Table.ExpandRecordColumn(Merge, "x", {"Количество", "Закупка", "Сумма закупки", "Продажа", "Сумма продажи","Дата"}),
    Renamed = Table.RenameColumns(Expand1,{{"Attribute:f34", "Товар"}, {"18", "Место реализации"}, {"19", "Товарная группа"}})
in
    Renamed    
Изменено: Андрей Лящук - 04.04.2020 16:51:01
 
Андрей Лящук, Спасибо (!) - буду разбираться.

Я подключил его к файлу "XML файл.xml" в самом первом посте.
Цитата
mitox : XML файл.rar  
И он выдает ошибку
Цитата
Expression.Error: Поле "xml" записи не найдено.
Сведения:
   Kind=Element
   Name=HTML
   Children=Table
   Text=
upd Выдает на строке "DataSet"
Изменено: mitox - 04.04.2020 15:18:32
 
Цитата
mitox написал:
Поле "xml" записи не найдено
'<table><tr><th>xml</th></r><tr><td>"&Source&"' замените на '<table><tr><th>xml</th></tr><tr><td>"&Source&"'
 
Видимо, в ваших двух примерах отличаются условия отбора, которые вы вводили, чтобы получить xml
 
Михаил Л, Спасибо. Заработало.
 
Еще раз огромное спасибо. На данных Предприятия все работает по любым периодам, даже при сокращении количества выгружаемых столбов (не являющихся ключевыми для работы обработчика)

UPD На выгрузке из файла( "XML файлM.xml") столкнулся с задачкой которую не могу победить
Цитата
DataFormat.Error: Сбой обработки XML. Введенные данные недопустимы или не поддерживаются. (Внутренняя ошибка: "", шестнадцатеричное значение 0x07, является недопустимым знаком., строка 1, позиция 1943.)
Сведения:
Уже и в Word скопировал список и там все излазил через поиск и с работающим файлом сравнил - ни чего не могу найти...

Помогите пожалуйста... Или подскажите куда копать...
Изменено: mitox - 04.04.2020 15:11:45
 
Андрей Лящук, Волшебник. Подскажите пожалуйста как искать ответ на свой вопрос? На два вопроса я уже нашел сам...

UPD Андрей Лящук,  Я сопоставил содержание двух обработок на этапе "Source" заменив "/&gt;\n" на "абзац" - и выгрузил в эксель, сопоставив колонки. Видно что структура справочников немного другая...  
Изменено: mitox - 04.04.2020 17:01:44
 
Андрей Лящук, здравствуйте
Можно узнать, как выгрузить xml в Excel ? Сложность в том, что встроенными средствами PQ выгружает таблицу таблиц. Дальше стопор
В архиве xml и желаемый результат
Код
= Xml.Tables(File.Contents("C:\ferre.xml"), null, 1251){0}[item]
 
Цитата
Михаил Л написал:
</r>
странно, что с таким косяком у меня работало, видимо сказались разные версии MSHML
mitox, ошибка лечится добавлением еще одной замены в шаге Source
Код
= Text.Replace(Text.Replace(Text.Replace(Text.Replace(Text.FromBinary(File.Contents("C:\Users\Krosav4ig\Desktop\XML файлM.xml")),"\","\\"),"#(cr,lf)","\n"),"<","<"),">",">")


и шаг Groups на случай, если в группе 53 не будет иерархии parent-child, как в последних 2х xml
Код
= let
        a = Table.Combine(List.Transform(List.RemoveNulls(DataSet[Groups]),each _{0}[g]))[[DataSet],[#"Attribute:pKey"]],
        b = Table.ReplaceValue(a,each [#"Attribute:pKey"],null,(a,b,c)=>
                let 
                    rec=a{0}[Records]{0}[r] 
                in 
                    if a{0}[Fields]{0}[f]{[#"Attribute:Id"="_GrpTreePerent_"]}?=null 
                        then if b = "53" then Table.RenameColumns(fnParentValuesRecursive(Table.Buffer(DataSet{[#"Attribute:Id"="209"]}[Records]{0}[r]),"Attribute:f3","Attribute:f0","Attribute:f5"),{"Attribute:f5","Attribute:f1"}) else rec
                        else fnParentValuesRecursive(Table.Buffer(rec),"Attribute:f2","Attribute:f0","Attribute:f1")
            ,{"DataSet"}),
        c = Table.ExpandTableColumn(Table.NestedJoin(b,"Attribute:pKey",DataSet{[#"Attribute:Id"="300"]}[Fields]{0}[f],"Attribute:Id","a"),"a",{"Attribute:n"}),
        d = Table.ExpandTableColumn(c, "DataSet", {"Attribute:f0", "Attribute:f1"})
    in Table.Buffer(d)


правильнее, конечно, было бы сформировать полный справочник товарных групп и хранить его, допустим, на листе и при обработке xml файлов брать названия из него, чтобы не вычислять по несколько раз одно и то же.
вам поле f20(в файле XML файлM.xml связь c группой по id 54) выводить нужно?
Изменено: Андрей Лящук - 05.04.2020 00:36:06
 
Цитата
Андрей Лящук написал:
ошибка лечится
Тёзка, ну, приношу свои извинения, но не могу не съязвить - а что просто парсингом штатными средствами работы с Xml - нельзя было обойтись? Всё же тоже самое было бы. :)
 
ну так жеж не интересно :)
я вначале вообще хотел xslt написать и через подключив в xml через xml-stylesheet скормить power query  :D
но для этого нужен веб-сервер, хотя бы локальный портативный
Код
=Web.Page(Web.Contents("http://localhost/file.xml"))
 
Цитата
Андрей Лящук написал: :idea:
ну так жеж не интересно
:D
 
Андрей Лящук, Спасибо за помощь. Заработал файл. Вчера уже голова кипела - сегодня, отдохнув, хотел разобраться именно в строке Sourse (вчера добавил в ней замену кавычек, чтоб заработал один из выложенных файлов).

Цитата
Андрей Лящук написал:
полный справочник товарных групп
У меня уже такой имеется частично - по этим же данным но повыгрузке из сопряжонной с этой программой. Я на текущем этапе отрабатываю загрузку данных в Базы данных к которым зацеплю Power BI.
Вторым этапом разберу весь винигрет который у меня получился и попробую структурировать получившуюся систему загрузки и обработки чтоб ускорить работу BI (на имеющемся оборудовании) - там уже буду работать со справочниками.

Цитата
Андрей Лящук написал:
вам поле f20(в файле XML файлM.xml связь c группой по id 54) выводить нужно?
Уже сделано больше чем достаточно. Спасибо. Проверил - вроде все что можно и нужно вытащить из xml - уже вытащено.
Цитата
Андрей VG написал:
парсингом штатными средствами работы с Xml - нельзя было обойтись?
День добрый. А о чем идет речь? Я когда сам пытался поискать в инете по теме перевода в xml в excel - несколько раз наталкивался на термин "парсить". Но так толком и не разобрался.
 
Цитата
Виктор А написал:
Можно узнать, как выгрузить xml в Excel ?
вариант с помощью xslt

качаем laragon portable , распаковываем, в папку www закидываем ferre.xml и Stylesheet.xslt , в ferre.xml после строки
Код
<?xml version="1.0" encoding="windows-1251"?>
добавляем строку
Код
<?xml-stylesheet type="text/xsl" href="Stylesheet.xslt"?>
Запускаем Laragon.exe Menu->Nginx->Start Nginx

Win+R
Код
Rundll32.exe inetcpl.cpl ShowWebsiteDataSettings
Вкладка "Временные фалы Интернета", отмечаем "При каждом посещении веб-страницы"


Stylesheet.xslt

Запрос в Power Query
Код
let
    Source = Web.Page(Web.Contents("http://localhost/ferre.xml"))[Data]{0}
in
    Source
Изменено: Андрей Лящук - 05.04.2020 18:31:05
 
Цитата
Андрей Лящук написал:
вариант с помощью xslt
- сила!!!
Страницы: 1 2 След.
Наверх