|  | 
|  01.11.2008, 13:49 | #1 | 
| Участник | Сериализация 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 | 
| Участник | 
			
			из xml в common - Global::recordFromXMLNode(). Наоборот готовой я не нашел, самому пришлось писать
		 | 
|  | |
| За это сообщение автора поблагодарили: kashperuk (2). | |
|  01.11.2008, 14:14 | #3 | 
| Боец | Цитата: 
		
			из 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 | 
| Участник | 
			
			Не знаю, как в других версиях, но в 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 | 
| Боец | 
			
			и в 3ке и в 4ке есть штатный механизм экспорта меток при экспорте элементов AOT с метками. Метки в xpo записываются в виде XML. Механизм, формирующий xml и обратно находится в упомянутых выше методах:  \Classes\SysImportLabel\label2Xml \Classes\SysImportLabel\xml2Label Так что если входной и выходной форматы и отличаются, то метод recordFromXMLNode() уже допилен, хотя на первый взгляд они не отличаются в 3-ке и 4-ке. | 
|  | 
|  01.11.2008, 15:37 | #6 | 
| Участник | 
			
			В методе xml2Label() идет вызов recordFromXMLNode(xmlDocument.documentElement(), tmp); Если вместо него подставить tmp = recordFromXMLNode(xmlDocument.documentElement());, то будет эксепшен. 
				__________________ Axapta v.3.0 sp5 kr2 | 
|  | 
|  30.06.2009, 07:25 | #7 | 
| Участник | Цитата: 
		
			Сообщение от 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()); } } 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()); 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); } ... } Вне зависимости от версии 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;
         ...X++:          ....
         case Types::Int64 :
            retval.value(#value, str2int64(getXmlNodeValue(n)));
            break;
          .... , однако совсем забыт новый тип 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 | 
| Участник | 
			
			Как оказалось, это еще не все неприятности, связанные с 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 | 
| Боец | 
			
			Там ещё была проблема с common.xml(); По-моему, был страшный взлет клиента, если common содержит memo поля. Пытался повторить но чё-то не получилось, так что be careful.
		 | 
|  | 
|  07.08.2009, 17:38 | #10 | 
| Участник | 
			
			у нас при попытке воспользоваться CustTable.xml() (есть поля memo) вылезает "Внутренняя ошибка 25 в сценарии." на каждое мемо поле, однако система не валится. Причем если посмотреть в полученный xml-файл, видно, что значение для поля мемо будет равно значению предыдущего поля. Как я понял, ошибка вылезает в \Classes\xRecord\xml(), а туда путь заказан.  DAX4.0 SP2EE FP1 Последний раз редактировалось Denicce; 07.08.2009 в 17:43. | 
|  | 
|  10.08.2009, 16:53 | #11 | 
| Участник | 
			
			Война с мемо-в-XML продолжается. Попробовал в Ах3.0 SP3 + SQL2005 - тот же эффект. Пробовал DAX4.0 SP1 + SQL2000 - аналогично. Может, подскажет кто, куда копать? | 
|  | 
|  10.08.2009, 17:02 | #12 | 
| Участник | |
|  | 
|  10.08.2009, 17:40 | #13 | 
| Боец | 
			
			 Это kernel функция, наверное не обойдешь никак, пока(если) не вылечат. Нарисуйте свою обертку XML, там ведь не сложно по сути.
		 | 
|  | 
|  12.08.2009, 16:49 | #14 | 
| Участник |   
			
			Продолжаем.... Метод 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; X++: case Types::Guid: retval.value(#value, str2guid(getXmlNodeValue(n))); break; | 
|  | 
| Теги | 
| ax2009, ax3.0, ax4.0, common, recordfromxmlnode, xml, баг, ошибка, сериализация | 
|  | 
| 
 |