Как сравнить две структуры данных?

Автор eeigor, 27 июля 2022, 08:31

0 Пользователи и 1 гость просматривают эту тему.

eeigor

Как сравнить разом две структуры данных css.table.CellAddress на равенство? Есть такая функция? Или проверять на совпадение по отдельности: Sheet, Column, Row?

Operator Is, EqualUnoObjects Function - это, кажется, всё не то: True, если ссылаются на один и тот же instance
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

#1
В Basic (как и в VBA) операторы сравнения определены для выражений (то есть, для скалярных типов). Попытка сравнивать массивы, пользовательские типы приводит к ошибке.
В VBA при сравнении объектов делается попытка сравнить свойства объектов по умолчанию. Как сравнивает объекты LO Basic c опцией VBA Support 1 - предмет отдельного изучения, без этой опции попытка сравнения объектов приведет к ошибке (так как нет понятия свойства по умолчанию).

Теоретически можно сравнить две UNO-структуры одного типа, последовательно сравнивая их элементы. У А.Питоньяка в книге OOME_4_0.odt есть суперсодержательный раздел "18.5. The object inspector example", в котором, в частности, показан путь и для интроспекции UNO-структур. Список свойств А.Питоньяк получает с помощью метода dbg_Properties; для получения значений свойств структур генерируется текст макроса на LO Basic, что явно нельзя признать "промышленным" решением.

Update. Функция CallByName появилась в документации и, похоже, работает. Так что путь открыт, сегодня-завтра напишем (на LO Basic)! Серпентологам проще, у них интроспекция объектов есть изначально.
Владимир.

eeigor

Цитата: sokol92 от 27 июля 2022, 12:58CallByName
Владимир, интересная функция... но с этим надо разбираться.
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

В первом приближении написал, можно пробовать.

' Сравнивает поэлементно Uno-структуры Struct1 и Struct2.
' Коды возврата:
' 0 - все имена свойств структуры Struct1 присутствуют в списке свойств структуры Struct2,
'     имеют тот же тип и значения свойств одинаковы.
' 2 - Struct1 или(и) Struct2 не является UNO-структурой.
' 1 - остальные случаи.
Function CompareUnoStruct(ByVal Struct1, ByVal Struct2) As Long
  Static oIntro As Object
  Dim oProp, val1, val2, pName As String, rc As Long
  If oIntro Is Nothing Then oIntro=GetDefaultContext().getValueByName("/singletons/com.sun.star.beans.theIntrospection")
  CompareUnoStruct=2
  If Not IsUnoStruct(Struct1) Then Exit Function
  If Not IsUnoStruct(Struct2) Then Exit Function
  CompareUnoStruct=1
  On Error GoTo ErrLabel
 
  For Each oProp In oIntro.Inspect(Struct1).getProperties(-1)
    pName=oProp.Name
    val1=CallByName(Struct1, pName, 2)
    val2=CallByName(Struct2, pName, 2)
    rc=CompareUnoStruct(val1, val2)
    If rc=2 Then rc=IIf(varType(val1)=varType(val2) And val1=val2, 0, 1)
    If rc<>0 Then CompareUnoStruct=rc : Exit Function
  Next oProp
  CompareUnoStruct=0
 
ErrLabel:
End Function
Владимир.

eeigor

#4
Владимир, вижу, что это очень полезная функция. Но мне нужно время, чтобы разобраться. Я выше не понял, зачем понадобилась функция CallByName, но здесь увидел ее в действии. rc - это результат рекурсивного вызова?

Я столкнулся с тем, что некоторые объекты (со своими структурами) при восстановлении данных (синхронизации) нельзя просто перезаписать (катастрофически возрастает время обновления), а надо обязательно проверить их на расхождение с эталоном (резервной копией). Таким объектом, к примеру, является NamedRange. При работе в окне менеджера имен (Manage Names) после обновления данных выполняется внутренняя сортировка имен, с изменением индекса в коллекции у каждого объекта.
Работаю над решением задачи, поднятой вот здесь. Мне эта тема показалась не безынтересной. К тому же я добавил парочку полей к именованному диапазону: HierachyLevel (для вложенных диапазонов-формульных выражений, то есть рассчитываемых на базе "родителя", например матрица - вектор матрицы) - у меня такая система именования активно используется (удобно: достаточно поправить головную ссылку, и всё пересчитается); Comment (как в Excel, в Calc, к сожалению, штатного такого свойства нет). Пока в работе, но близко к завершению (детали форматирования)...
Кого-нибудь заинтересовало?

У меня в одном проекте больше 40 именованных диапазонов/формульных выражений, как глобальных, так и локальных.
Пример иерархии показан ниже (уровень задается пользователем вместе с комментарием к имени; отступ вводится автоматически; синхронизация главной таблицы имен и таблицы с добавленными свойствами выполняется по составному ключу: Scope, Name - и при выгрузке данных заново пользовательские данные (custom properties) совмещаются и не пропадают).

Примечание. В свойстве ReferencePosition (та опорная ячейка, используемая при относительной адресации) к моему удивлению обнаружился полный хаос, а лучше этого не делать... :) Ссылка Кови_ЭтаФИО - относительная и требует правильной установки референсной ячейки. Другие ссылки в примере ниже абсолютные, и в поле Reference cell name - полная каша (пользователь не заботится об этом, а Calc всё записывает).
Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community

sokol92

Цитата: eeigor от 27 июля 2022, 22:08зачем понадобилась функция CallByName, но здесь увидел ее в действии. rc - это результат рекурсивного вызова?
Функция CallByName (как и ее сестра-близнец) позволяет динамически указывать свойства и методы объекта, в отличие от статической конструкции Объект.Свойство. C третьим параметром, равным 2 (vbGet), она делает то же, что и метод getPropertyByName, но структуры UNO не имеют методов (с оговорками).
Рекурсивный вызов сделан для тех случаев, когда значение свойства UNO-структуры является UNO-структурой.
Обратите также внимание на использование метода inspect вместо устаревших конструкций dbg_Properties и др. у А.Питоньяка.
Владимир.

eeigor

Ubuntu 18.04 LTS • LibreOffice 7.5.1.2 Community