AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 01.11.2008, 13:49   #1  
axbegin is offline
axbegin
Участник
 
14 / 10 (1) +
Регистрация: 16.06.2008
Сериализация common в xml
А есть ли готовый код, сериализующий запись в xml. То есть, интересует функция, принимающая на вход common и выдающая на выходе xml примерно такого вида:

<?xml version="1.0"?>
<record id="0000004" author="А" status="Закрыто" priority="Средний" description="some text"/>

Атрибуты элемента являются всеми столбцами таблицы. Имена атрибутов - имена столбцов. Значение атрибутов - значение столбцов.

Ну и соответвенно есть ли обратная процедура, которая из xml заполняет common.

Схема xml может быть и другая.
Старый 01.11.2008, 13:59   #2  
Lucky13 is offline
Lucky13
Участник
1C
 
714 / 198 (8) ++++++
Регистрация: 21.10.2004
из xml в common - Global::recordFromXMLNode(). Наоборот готовой я не нашел, самому пришлось писать
За это сообщение автора поблагодарили: kashperuk (2).
Старый 01.11.2008, 14:14   #3  
DSPIC is offline
DSPIC
Боец
 
1,077 / 1243 (44) ++++++++
Регистрация: 11.04.2008
Цитата:
из xml в common - Global::recordFromXMLNode(). Наоборот готовой я не нашел, самому пришлось писать
Готовая - ещё проще:
xml = common.xml();

для примера смотри:
\Classes\SysImportLabel\label2Xml
\Classes\SysImportLabel\xml2Label

Последний раз редактировалось DSPIC; 01.11.2008 в 14:17. Причина: пример
За это сообщение автора поблагодарили: kashperuk (2), Lucky13 (2), plumbum (1).
Старый 01.11.2008, 15:09   #4  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
Не знаю, как в других версиях, но в ax3 kr2 форматы передаваемый в recordFromXMLNode() и получаемый из xRecord.xlm() - несколько различаются. Если вызывать recordFromXMLNode() без передачи табличного буфера в метод, то таблица, содержащаяся в xml не будет определена и будет вызвано прерывание.
По-этому, либо надо будет парсить xml для опраделения таблицы до передачи в метод, либо надо будет знать заранее, какая таблица там будет

X++:
static void xml2record(Args args)
{
    InventTable InventTable;
    Common  common;
    xmlDocument xmlDocument = new xmlDocument();
    XMLNode xmlNode;
    ;
    select InventTable;
    if (xmlDocument.loadXML(InventTable.xml()))
    {
        xmlNode = xmlDocument.documentElement();
        if (xmlNode.nodeName() == "Table:Record")
        {
            common = new DictTable(tableName2Id(xmlNode.attributes().getNamedItem("name").nodeValue())).makeRecord();
            global::recordFromXMLNode(xmlDocument.documentElement(), common);
        }
        else
            common = global::recordFromXMLNode(xmlDocument.documentElement());
    }
}
__________________
Axapta v.3.0 sp5 kr2

Последний раз редактировалось AndyD; 01.11.2008 в 15:28.
Старый 01.11.2008, 15:27   #5  
DSPIC is offline
DSPIC
Боец
 
1,077 / 1243 (44) ++++++++
Регистрация: 11.04.2008
и в 3ке и в 4ке есть штатный механизм экспорта меток при экспорте элементов AOT с метками. Метки в xpo записываются в виде XML. Механизм, формирующий xml и обратно находится в упомянутых выше методах:
\Classes\SysImportLabel\label2Xml
\Classes\SysImportLabel\xml2Label
Так что если входной и выходной форматы и отличаются, то метод recordFromXMLNode() уже допилен, хотя на первый взгляд они не отличаются в 3-ке и 4-ке.
Старый 01.11.2008, 15:37   #6  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
В методе xml2Label() идет вызов recordFromXMLNode(xmlDocument.documentElement(), tmp);
Если вместо него подставить tmp = recordFromXMLNode(xmlDocument.documentElement());, то будет эксепшен.
__________________
Axapta v.3.0 sp5 kr2
Старый 30.06.2009, 07:25   #7  
SRF is offline
SRF
Участник
MCBMSS
Axapta Retail User
 
375 / 562 (19) +++++++
Регистрация: 08.08.2007
Записей в блоге: 1
Цитата:
Сообщение от AndyD Посмотреть сообщение
...По-этому, либо надо будет парсить xml для опраделения таблицы до передачи в метод, либо надо будет знать заранее, какая таблица там будет

X++:
static void xml2record(Args args)
{
    InventTable InventTable;
    Common  common;
    xmlDocument xmlDocument = new xmlDocument();
    XMLNode xmlNode;
    ;
    select InventTable;
    if (xmlDocument.loadXML(InventTable.xml()))
    {
        xmlNode = xmlDocument.documentElement();
        if (xmlNode.nodeName() == "Table:Record")
        {
            common = new DictTable(tableName2Id(xmlNode.attributes().getNamedItem("name").nodeValue())).makeRecord();
            global::recordFromXMLNode(xmlDocument.documentElement(), common);
        }
        else
            common = global::recordFromXMLNode(xmlDocument.documentElement());
    }
}
Либо для AX 3.0 можно внести изменение в метод recordFromXMLNode (так же можно навсякий случай учитывать и атрибут 'table')
X++:
// Input is <Record table="name"> <Field:field1> value </Field:field1> ... </Record>
static common recordFromXMLNode(XMLNode n, Common c = null)
{
    TableId table;
    FieldId field;
    dictTable dt;
    dictField df;
    XMLNode fieldNode;
    str fieldName;
    struct content;
    // If we don't have an incoming buffer, one is created
    if (prmIsDefault(c))
    {
        // Create a buffer of the correct type
        //srf -->
        //table = tableName2Id(n.attributes().getNamedItem('table').nodeValue());
        table = tableName2Id(n.attributes().getNamedItem('name').nodeValue());
        //srf <--
        dt = new dictTable(table);
        c = dt.makeRecord();
    }
    else
    {
        table = c.TableId;
        dt = new dictTable(table);
    }
    ...
}
После этого можно пользоваться вызовом
X++:
common = global::recordFromXMLNode(xmlDocument.documentElement());
без передачи табличной переменной вторым параметром. В AX 2009 в данном методе именно так и делается(еще также учитывается атрибут 'table') :
X++:
// Input is <Record table="name"> <Field:field1> value </Field:field1> ... </Record>
static Common recordFromXMLNode(XmlNode n, Common c = null)
{
    tableId table;
    fieldId field;
    DictTable dt;
    DictField df;
    XmlNode fieldNode;
    str fieldName;
    Struct content;
    XmlNode tableName;
    Types t;
    //validate arguments before using them
    if (n == null)
        return null;
    // If we don't have an incoming buffer, one is created
    if (prmisdefault(c))
    {
        // Create a buffer of the correct type
        tableName = n.attributes().getNamedItem('name');
        // If node does not contain name attribute, try with table attribute.
        if (tableName == null)
        {
            tableName = n.attributes().getNamedItem('table');
        }
        // Check if table node can be accessed
        if (tableName != null)
        {
            table = tablename2id(tableName.nodeValue());
            dt = new DictTable(table);
            c = dt.makeRecord();
        }
    }
    else
    {
        table = c.TableId;
        dt = new DictTable(table);
    }
...
}
Есть и еще неприятные моменты и ошибки возникающие при работе с recordFromXMLNode

Вне зависимости от версии AX (3.0, 4.0, 2009), если в таблице есть поле типа Container - то при сериализации записи c помощью common.xml() и обратном преобразовании с помощью recordFromXMLNode вылетает эксепшен. Чтобы побороть данную ошибку нужно внести изменение Global::valueFromXmlNode
X++:
         ....
         case Types::Container :
            //srf -->
            //retval.value(#value, Global::containerFromXMLNode(n));
            retval.value(#value, Global::containerFromXMLNode(n.firstChild()));
            //srf <--
            break;
         ...
Для AX 4.0 (SP2 в том числе) не учитываются поля типа int64, т.е. нужно как минимум в метод Global::valueFromXmlNode добавить case по типу int64
X++:
         ....
         case Types::Int64 :
            retval.value(#value, str2int64(getXmlNodeValue(n)));
            break;
          ....
Для AX 2009 поле типа int64 учитывается , однако совсем забыт новый тип UtcDateTime, чтобы поля данного типа заполнялись в метод Global::valueFromXmlNode нужно добавить соотвествующий case
X++:
...
case Types::UtcDateTime :
            retval.value(#value, str2datetime(getXmlNodeValue(n), -1));
            break;
...

Последний раз редактировалось SRF; 30.06.2009 в 07:27.
За это сообщение автора поблагодарили: gl00mie (7).
Старый 09.07.2009, 06:30   #8  
SRF is offline
SRF
Участник
MCBMSS
Axapta Retail User
 
375 / 562 (19) +++++++
Регистрация: 08.08.2007
Записей в блоге: 1
Как оказалось, это еще не все неприятности, связанные с recordFromXMLNode. Недавно коллега обнаружил еще пару интересных моментов.

Независимо от версии AX 3.0, AX 4.0 или AX2009 через метод recordFromXMLNode не загружаются поля-массивы записей, поскольку атрибут offset (формируемый при помощи common.xml()) никак не учитывается.

А коде функции valueFromXMLNode (используется в recordFromXMLNode)
X++:
boolean enum; // Any enumeration type will do...
 
...
 
case Types::Enum :
    enum = str2int(getXmlNodeValue(n));
    retval.value(#value, enum);
    break;


Т.е. для enum-ов можно увидеть преобразование int -> boolean, как следствие, некорректная загрузка значений enum'ов, данная ошибка наблюдается только в версиях младше AX 2009, там починили следующим образом
X++:
...
t = df.baseType();
 
if (t == Types::Enum)
    t = Types::Integer;
 
content = valueFromXmlNode(t, fieldNode);
...
После всех этих ошибок, в голову пришли вопросы
Цитата:
А вообще common.xml() и global::recordFromXMLNode это обратные функции или нет? Может есть другие обратные для ниx?
Буду рад услышать комментарии по данным вопросам.

Пока для себя решил, что это обратные функции(то, как они используются в AX, говорит как раз об этом), и те ошибки, которые допущены в реализации recordFromXMLNode и valueFromXMLNode, в последующих версиях должны, как мне кажется, быть устранены

А пока ниже приведен код метода recordFromXMLNode для AX 4.0, устраняющий обе эти ошибки
X++:
// Input is <Record table="name"> <Field:field1> value </Field:field1> ... </Record>
static Common recordFromXMLNode(XmlNode n, Common c = null)
{
    tableId table;
    fieldId field;
    DictTable dt;
    DictField df;
    XmlNode fieldNode;
    str fieldName;
    Struct content;
    // -->
    XmlNode     fieldArrayNode;
    int         fieldArray;
    // <--
    //validate arguments before using them
    if (n == null)
        return null;
    // If we don't have an incoming buffer, one is created
    if (prmisdefault(c))
    {
        // Create a buffer of the correct type
        table = tablename2id(n.attributes().getNamedItem('table').nodeValue());
        dt = new DictTable(table);
        c = dt.makeRecord();
    }
    else
    {
        table = c.TableId;
        dt = new DictTable(table);
    }
    fieldNode = n.firstChild();
    while (fieldNode)
    {
        fieldName = fieldNode.attributes().getNamedItem('name').text();
        field = dt.fieldName2Id(fieldName);
        df = new DictField(table, field);
        // -->
        fieldArrayNode = fieldNode.attributes().getNamedItem('offset');
        if (fieldArrayNode)
        {
            fieldArray = str2int(fieldArrayNode.text());
            if (fieldArray)
            {
                field = fieldId2Ext(field, fieldArray);
            }
        }
        if (df.baseType() == Types::Enum)
        {
            content = valueFromXMLNode (Types::Integer, fieldNode);
        }
        else
        // <--
        content = valueFromXMLNode (df.baseType(), fieldNode);
        c.(field) = content.value('value');
        fieldNode = fieldNode.nextSibling();
    }
    return c;
}
За это сообщение автора поблагодарили: AlGol (3).
Старый 09.07.2009, 08:33   #9  
DSPIC is offline
DSPIC
Боец
 
1,077 / 1243 (44) ++++++++
Регистрация: 11.04.2008
Там ещё была проблема с common.xml(); По-моему, был страшный взлет клиента, если common содержит memo поля. Пытался повторить но чё-то не получилось, так что be careful.
Старый 07.08.2009, 17:38   #10  
Denicce is offline
Denicce
Участник
 
62 / 54 (2) ++++
Регистрация: 22.03.2005
Адрес: Москва
у нас при попытке воспользоваться CustTable.xml() (есть поля memo) вылезает "Внутренняя ошибка 25 в сценарии." на каждое мемо поле, однако система не валится. Причем если посмотреть в полученный xml-файл, видно, что значение для поля мемо будет равно значению предыдущего поля.
Как я понял, ошибка вылезает в \Classes\xRecord\xml(), а туда путь заказан.

DAX4.0 SP2EE FP1

Последний раз редактировалось Denicce; 07.08.2009 в 17:43.
Старый 10.08.2009, 16:53   #11  
Denicce is offline
Denicce
Участник
 
62 / 54 (2) ++++
Регистрация: 22.03.2005
Адрес: Москва
Война с мемо-в-XML продолжается.
Попробовал в Ах3.0 SP3 + SQL2005 - тот же эффект. Пробовал DAX4.0 SP1 + SQL2000 - аналогично.
Может, подскажет кто, куда копать?
Старый 10.08.2009, 17:02   #12  
egorych is offline
egorych
Участник
Самостоятельные клиенты AX
Oracle
 
761 / 154 (7) ++++++
Регистрация: 09.11.2006
Адрес: Краснодарский край
Цитата:
Сообщение от Denicce Посмотреть сообщение
Может, подскажет кто, куда копать?
Воспользоваться человеческим языком (SQL)
X++:
SELECT * FROM Table
FOR XML RAW;
Старый 10.08.2009, 17:40   #13  
DSPIC is offline
DSPIC
Боец
 
1,077 / 1243 (44) ++++++++
Регистрация: 11.04.2008
Цитата:
Сообщение от Denicce Посмотреть сообщение
Война с мемо-в-XML продолжается.
Попробовал в Ах3.0 SP3 + SQL2005 - тот же эффект. Пробовал DAX4.0 SP1 + SQL2000 - аналогично.
Может, подскажет кто, куда копать?
Это kernel функция, наверное не обойдешь никак, пока(если) не вылечат. Нарисуйте свою обертку XML, там ведь не сложно по сути.
Старый 12.08.2009, 16:49   #14  
Denicce is offline
Denicce
Участник
 
62 / 54 (2) ++++
Регистрация: 22.03.2005
Адрес: Москва
!
Продолжаем....
Метод Global::valueFromXmlNode, не хватает case для memo (VarString хоть и описан, но вылетает ошибка "Ожидался memo, получен str", и struct retval не принимает строку).
Посему: выделил VarString отдельно, но сделал, как мне кажется, коряво:
X++:
        case Types::VarString :
            retval = new Struct(Types::String, #value);
            retval.value(#value, getXmlNodeValue(n));
            break;
и не хватает case для types::guid:
X++:
        case Types::Guid:
            retval.value(#value, str2guid(getXmlNodeValue(n)));
            break;
Теги
ax2009, ax3.0, ax4.0, common, recordfromxmlnode, xml, баг, ошибка, сериализация

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
dax-lessons: Generate XML Documentation Files for a project - DAX 2009 Blog bot DAX Blogs 0 08.08.2008 19:06
axStart: How to use XSLT in AIF and what’s wrong with empty xml Nodes. Blog bot DAX Blogs 0 27.04.2008 18:07
Inside Dynamics AX 4.0: Common Search Blog bot DAX Blogs 0 29.10.2007 10:50
Inside Dynamics AX 4.0: The XML Structure Blog bot DAX Blogs 0 04.10.2007 11:20
Inside Dynamics AX 4.0: XML Document Integration Blog bot DAX Blogs 0 04.10.2007 11:20

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 19:24.