>Форум Mozilla Россия http://forum.mozilla-russia.org/index.php >Разработка http://forum.mozilla-russia.org/viewforum.php?id=18 >Источники данных: RDF vs. XML [vs SQLite] http://forum.mozilla-russia.org/viewtopic.php?id=51897 |
hydrolizer > 11-10-2011 04:57:14 |
Недавно понадобилось сделать одну функциональность, в которой используется отображение и редактирование иерархических данных в xul:tree. Поскольку реализация custom nsITreeView - дело нехитрое, и не раз пройденное, то, чтобы жизнь медом не казалась, я решил сделать дерево на основе rdf-источника. В процессе разбора документации я обнаружил, что, оказывается, на данный момент в качестве источников данных поддерживаются и шаблоны на основе XML, и даже SQLite-шаблоны. В свое время, пытаясь для себя уяснить специфику rdf-шаблонов, я был не особенно в восторге от её реализации (впечатление на тот момент - перегруженное достаточно неочевидной логикой надмножество XML). Теперь же источники данных вполне можно проектировать на основе XML, используя в качестве основы запросов давно известные и понятные XPath-выражения. Но здесь есть одно "но": RDF - фактически родная технология Mozilla, очень давно поддерживаемая, и хорошо обкатанная. Шаблоны и источники данных на других основах появились, насколько я понял, сравнительно недавно. Поэтому, если кому-то доводилось оценивать плюсы и минусы от использования перечисленных источников, то хотелось бы услышать мнение, какие источники данных всё же предпочтительнее использовать на данный момент. |
hydrolizer > 12-10-2011 18:45:52 |
В результате экспериментов выяснилось следующее. Самый главный минус источников данных, отличных от rdf - очень скудная документация по работе c этими источниками. Если для rdf можно найти примеры кода почти на все случаи жизни, то для того же XML - только самые простейшие примеры. скрытый текст Выделить код Код:<?xml version="1.0" encoding="UTF-8"?> <root> <item name="ItemA" /> <group type="GroupA"> <item name="ItemAA" /> <group type="GroupAB"> <item name="ItemABA" /> <item name="ItemABB" /> </group> <item name="ItemAB" /> </group> <item name="ItemB" /> <group type="GroupB"> <item name="ItemBA" /> <item name="ItemBB" /> </group> <item name="ItemC" /> </root> Стандартный пример, предлагаемый для построения дерева на основе XML: скрытый текст Выделить код Код:<tree id="xmltree" flex="1" datasources="chrome://addondevhelper/content/items.xml" ref="*" querytype="xml" flags="dont-build-content"> <treecols> <treecol id="name" primary="true" label="Name" flex="1"/> </treecols> <template> <query expr="*"/> <action> <treechildren> <treeitem uri="?"> <treerow> <treecell label="?name"/> </treerow> </treeitem> </treechildren> </action> </template> </tree> скрытый текст Выделить код Код:<tree id="xmltree" flex="1" datasources="chrome://xmltest/content/items.xml" ref="*" querytype="xml" flags="dont-build-content"> <treecols> <treecol id="name" primary="true" label="Name" flex="1"/> </treecols> <template> <queryset> <query expr="group"/> <action> <treechildren> <treeitem uri="?"> <treerow> <treecell label="?type"/> </treerow> </treeitem> </treechildren> </action> </queryset> <queryset> <query expr="item"/> <action> <treechildren> <treeitem uri="?"> <treerow> <treecell label="?name"/> </treerow> </treeitem> </treechildren> </action> </queryset> </template> </tree> скрытый текст - т.е. нарушается очередность следования узлов одного уровня, но разных типов - контейнеры группируются вверху родительского узла, листья - внизу. Как избежать такой ситуации - не знаю. И если для дерева можно вернуться (хотя бы обработав начальный xml с помощью xslt) к первоначальному варианту с одним запросом, который сохраняет порядок узлов, то, например, в случае с генерируемым на основе XML-источника меню такой фокус уже не выйдет - там в любом случае нужно как минимум 2 запроса: скрытый текст Выделить код Код:<button label="xml menu" type="menu" datasources="chrome://xmltest/content/items.xml" ref="*" querytype="xml"> <template> <queryset> <query expr="group"/> <action> <menupopup> <menu uri="?" label="?type"/> </menupopup> </action> </queryset> <queryset> <query expr="item"/> <action> <menupopup> <menuitem uri="?" label="?name"/> </menupopup> </action> </queryset> </template> </button> Единственное, что пока приходит в голову - на все ноды повесить атрибут порядкового номера со сквозной нумерацией сверху вниз. Но и тут тоже не всё так просто: если в rdf-документе можно указать атрибут parseType, то для xml этого сделать нельзя, даже если ввести переменную, в которой будет значение от атрибута порядкового номера, преобразованного в число - все равно сортировка таких чисел работает по алгоритму сортировки строк, и поэтому порядковый атрибут обязательно должен иметь лидирующие нули. Поэтому вопрос о нормальной генерации дерева пока остается открытым. |
hydrolizer > 30-10-2011 08:27:49 |
Сухой остаток от данной темы: деревья с автоматически генерируемым по шаблону контентом достаточно удобны, если требуется только отображение контента, и не требуется редактирования. Потому что при заданном флаге dont-build-content внесенные изменения вообще не подхватываются деревом, и для элементов сгенерированного дерева не возникает событий drag'n'drop. А при не заданном флаге dont-build-content всего этого нет, но внесенные изменения не проецируются на builder datasource; метода для синхронизации datasource с данными в дереве я не нашел. Наверное, можно как-то спроецировать эти данные с помощью предоставляемых билдером nsITemplateResult, либо навесить на дерево листенеры, и в них менять исходные данные - но это мне видится очень муторным занятием; способа разом получить источник, содержащий измененные данные, нет, а из-за этого теряется весь смысл работы с таким типом деревьев - овчинка просто не стоит выделки. С помощью старого проверенного nsITreeView можно легко сделать всё то же самое. К тому же есть дополнительные проблемы с локализацией контента дерева, и проблемы, если в дереве нужно отображать сепараторы - это опять несколько запросов на дерево, проблемы с сортировкой, и т.д. Выделить код Код:<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml"/> <xsl:template match="*"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:attribute name="ord"> <xsl:number count="*" level="any" format="000001"/> </xsl:attribute> <xsl:apply-templates/> </xsl:copy> </xsl:template> </xsl:stylesheet> и для контейнера меню дополнительно задать sort="?ord" sortDirection="ascending" |
hydrolizer > 11-11-2011 07:07:30 |
Всё-таки не дает покоя мне эта тема, и видимо, вернусь к ней я еще не раз. Выделить код Код:<?xml version="1.0" encoding="UTF-8"?> <root id="0"> <item id="1" name="ItemA" color="green"/> <item id="2" name="GroupA" color="yellow" exticon="jolly"> <item id="3" name="ItemAA" color="blue"/> <item id="4" name="GroupAB"> <item id="5" name="ItemABA" color="red"/> <separator id="13"/> <item id="6" name="ItemABB" /> </item> <item id="7" name="ItemAB" color="lightgray"/> </item> <item id="8" name="ItemB" /> <separator id="14"/> <item id="9" name="GroupB"> <item id="10" name="ItemBA" color="dialog"/> <item id="11" name="ItemBB" /> </item> <item id="12" name="ItemC" /> </root> XUL: Выделить код Код:<tree id="xmltree" flex="1" datasources="chrome://xmltemplatetest/content/items.xml" ref="*" querytype="xml" _flags="dont-build-content" draggable="true" editable="true"> <treecols> <treecol id="name" primary="true" label="Name" flex="1"/> </treecols> <template> <query expr="*"> <assign var="?nodename" expr="local-name(.)"/> <assign var="?props" expr="concat(@color, ' ', @exticon)"/> </query> <rule> <conditions> <where subject="?nodename" value="separator" rel="equals" ignorecase="true"/> </conditions> <action> <treechildren> <treeseparator uri="?" srcid="?id"/> </treechildren> </action> </rule> <rule> <conditions> <where subject="?nodename" value="item" rel="equals" ignorecase="true"/> </conditions> <action> <treechildren> <treeitem uri="?" srcid="?id"> <treerow properties="?props"> <treecell label="?name" properties="?props"/> </treerow> </treeitem> </treechildren> </action> </rule> </template> </tree> <button id="xml-menu-button" label="xml-generated menu" type="menu" querytype="xml" datasources="chrome://xmltemplatetest/content/items.xml" ref="*"> <template> <query expr="*"> <assign var="?count" expr="count(*)"/> <assign var="?nodename" expr="local-name(.)"/> </query> <rule> <conditions> <where subject="?count" value="0" rel="greater"/> </conditions> <action> <menupopup> <menu uri="?" label="?name" id="?id" color="?color" exticon="?exticon" class="menu-iconic"/> </menupopup> </action> </rule> <rule> <conditions> <where subject="?count" value="0" rel="equals"/> <where subject="?nodename" value="item" rel="equals" ignorecase="true"/> </conditions> <action> <menupopup> <menuitem uri="?" label="?name" id="?id" color="?color" exticon="?exticon" class="menuitem-iconic"/> </menupopup> </action> </rule> <rule> <conditions> <where subject="?nodename" value="separator" rel="equals" ignorecase="true"/> </conditions> <action> <menupopup> <menuseparator uri="?" id="?id"/> </menupopup> </action> </rule> </template> </button> Стиль: Выделить код Код:treechildren::-moz-tree-row(green) { background-color: lime; } treechildren::-moz-tree-row(red) { background-color: red; } treechildren::-moz-tree-row(yellow) { background-color: yellow; } treechildren::-moz-tree-row(blue) { background-color: lightblue; } treechildren::-moz-tree-row(lightgray) { background-color: lightgray; } treechildren::-moz-tree-row(dialog) { background-color: -moz-dialog; } treechildren::-moz-tree-row(yellow, jolly) { background-color: magenta; } treechildren::-moz-tree-image(open) { list-style-image: url(folderopen.png); } treechildren::-moz-tree-image(open, jolly) { list-style-image: url(jr.png); } treechildren::-moz-tree-image(closed) { list-style-image: url(folder.png); } menu[color], menuitem[color] { -moz-appearance: none; } menu { list-style-image: url(folder.png); } menu[open] { list-style-image: url(folderopen.png); } menu[open][exticon="jolly"] { list-style-image: url(jr.png); } menu[color="green"], menuitem[color="green"] { background-color: lime; } menu[color="red"], menuitem[color="red"] { background-color: red; } menu[color="yellow"], menuitem[color="yellow"] { background-color: yellow; color: black; } menu[color="blue"], menuitem[color="blue"] { background-color: lightblue; } menu[color="lightgray"], menuitem[color="lightgray"] { background-color: lightgray; } menu[color="dialog"], menuitem[color="dialog"] { background-color: -moz-dialog; } Результат выглядит примерно так: Примечания к коду: во-первых, не получилось использовать treeseparator в дереве с флагом dont-build-content - что-то вроде бы появляется, но как сепаратор оно не выглядит. Без флага dont-build-content всё в порядке. Некоторым объяснением этому может служить упоминание в документации о том, что с флагом dont-build-content в дереве надо использовать не контентные элементы, а элемент treeitem. |
tenshi > 12-11-2011 12:52:13 |
через e4x как-то так: |
hydrolizer > 12-11-2011 16:16:39 |
okkamas_knife пишет
Плохое решение. C xml надо работать как с DOM-документом, а не как со строкой. Соответствующими методами - getElementById, appendChild, возможно - XPath, и т.д. |
hydrolizer > 12-11-2011 20:56:25 |
okkamas_knife пишет
Слэш заэкранировать нужно. Т.е. в строку вписывать "\\n". 12-11-2011 21:19:17 |
YuryL > 28-11-2011 20:04:04 |
hydrolizer вопрос как к специалисту по nsITreeView я сейчас делаю приложение(на xulrunner), которое работает с древовидными данными. |
hydrolizer > 29-11-2011 06:39:15 |
YuryL |
YuryL > 29-11-2011 20:05:33 |
не нашел описания nsXULTreeBuilder в MDN ведь мне нужно свойству view дерева задать объект, который реализован на с++. Либо в коде с++ каким-то образом это сделать. Где можно почитать об этом? |
hydrolizer > 30-11-2011 06:30:40 |
YuryL пишет
Его там как такового нет, потому что это - реализация интерфейса, о чем я писал выше. Описания самих интерфейсов, и описания способов работы посредством спец. элементов (template/query/rule etc.) - есть. Но если вам хочется взглянуть на детали реализации - смотрите здесь: http://mxr.mozilla.org/mozilla-central/ … uilder.cpp YuryL пишет
А как вы обычно получаете экземпляр XPCOM-компонента? Точно так же и здесь: Интерфейс экземпляра полученного класса должен соответствовать контракту интерфейса nsITreeView. И если это так, то далее просто |
YuryL > 01-12-2011 01:06:24 |
спасибо, мне не верилось, что свойству view может быть присвоена, как ссылка на объект в двоичном коде, так и на js-объект, который будет интерпретироваться. ЗдОрово! Буду пробовать.. Кстати, еще вопрос, позволяет ли VS 2010 отлаживать XPCOM компоненты, т.е. будут ли срабатывать точки останова в среде VS 2010? |
hydrolizer > 01-12-2011 07:10:44 |
YuryL пишет
Не знаю - я пока что обходился простым отладочным выводом в консоль - не в консоль ошибок FF, а в консоль windows. Для этого достаточно обычного printf - например, и при запуске FF с консолью (нужно добавить ключ -console в строку запуска FF) будет примерно следующее: скрытый текст Разумеется, что достаточно сложный код таким образом отлаживать неудобно. Вот тут: http://www.iosart.com/firefox/xpcom/ человек пишет, что
Здесь: http://www.codeproject.com/KB/miscctrl/ … ation.aspx автор также пишет, что
так что вполне возможно, что и VS2010 позволит пошаговую отладку. Попробуйте. |
YuryL > 06-12-2011 12:09:53 |
С файлом nsXULTreeBuilder.cpp не получается разобраться, даже откомпиллировать. |