barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

вторник, 6 декабря 2011 г.

Расширение Firefox: Получение пути к файлу xpi-пакета расширения из JavaScript

Задача:
Из JavaScript-кода расширения Firefox получить путь (полноценный абсолютный путь файловой системы) к какому-либо файлу из xpi-пакета приложения, который при установке расширения распаковывается в AppData пользователя. Например, пусть нужен путь к файлу ext.dll, размещенного в папке "components/" xpi-архива, для его последующей загрузки функцией ctypes.open() библиотеки ctypes.

Решение:
Для версий Firefox 4.0+ (Gecko 2.0 и выше) имеется компонент AddonManager, предназначенный для работы с расширениями, и, в частности, позволяющий получать абсолютные пути к любым ресурсам расширения следующим образом:
addonId = "myaddon@somesite.org";// id, указанный в теге <em:id> install.rdf расширения
Components.utils.import("resource://gre/modules/AddonManager.jsm");
AddonManager.getAddonByID(addonId, function(addon)
{
var uri = addon.getResourceURI("components/ext.dll");
if (uri instanceof Components.interfaces.nsIFileURL && uri.file.path)
{
// работаем с путем uri.file.path, например, сохраняем его в какой-нибудь переменной, видимой снаружи
}
else
console.debug(addonId+": getAddonByID callback: uri is not Components.interfaces.nsIFileURL or uri.file.path is null or empty");
});
Однако, если Вам необходимо, чтобы Ваше расширение работало и в Firefox 3.6, придется изменить подход (вернее, можно использовать код, приведенный выше, для новых FF, и отдельный код для 3.6). Вызвана такая необходимость отсутствием в 3.6 AddonManager`а. Выход следующий: разместить файл, к которому нужно получить доступ, в chrome-реестре браузера, после чего воспользоваться преобразованием Chrome URI -> путь файловой системы. Размещение файла в chrome-реестре описывается в chrome.manifest файле расширения. В моем случае оно выглядело так (я продублировал нужную мне dll-ку, поместив её также в chrome/content/ xpi-пакета):
content     myaddon     chrome/content/
Теперь моя dll-ка доступна по chrome-пути "chrome://myaddon/content/ext.dll" (можно проверить, набрав такой URL в браузере). Для того, чтобы получить к ней абсолютный путь файловой системы, понадобится чуть больше кода, чем для 2ого Gecko (для работы данного кода нужен также енкодер/декодер URL, код которого я приводил тут):
/**
* Создает объект URI (реализующий интерфейс nsIURI) из переданной строки-URI, и, опционально, кодировки и базового URI
*/
function makeURI(aURL, aOriginCharset, aBaseURI)
{
var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
return ioService.newURI(aURL, aOriginCharset, aBaseURI);
}
/**
* Получает путь в фаловой системе к объекту, хранимому в chrome-реестре FF.
*/
function getFilepathFromChromeURL(chromeURL)
{
var chromeRegistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"].getService(Components.interfaces.nsIChromeRegistry);
var convertedURI;
try
{
convertedURI = chromeRegistry.convertChromeURL(makeURI(chromeURL,null,null));
}
catch(ex)
{
return false; }
if(convertedURI.scheme!="file")
return false;
return Url.decode(convertedURI.path.substring(1));
}
myPath = getFilepathFromChromeURL("chrome://myaddon/content/ext.dll");
В итоге в переменной myPath мы получим абсолютный путь к искомому файлу или false при ошибке.

понедельник, 5 декабря 2011 г.

Создание Document из строки в Orbeon

Подходы для парсинга строки в дерево Document на JavaScript различаются в разных браузерах (в IE используется ActiveX-компонент Microsoft.XMLDOM, в Firefox - XMLSerializer), но при написании кода для Orbeon можно использовать его кроссбраузерную функцию ORBEON.util.Dom.stringToDom().

пятница, 2 декабря 2011 г.

Создание подписи XML Signature, независимой от пространств имен, объявленных выше по иерархии по отношению к подписываемому узлу, но реально не использующихся внутри подписываемого поддерева

При использовании метода канонизации xml-документа "Canonical XML" (http://www.w3.org/TR/2001/REC-xml-c14n-20010315) получаемая подпись (здесь речь идет о случае, когда подписывается один узел xml-дерева, а не весь документ целиком) будет зависеть от пространств имен, объявленных в элементах выше по иерархии в дереве по отношению к подписываемому узлу, даже если эти пространства не используются внутри подписываемого поддерева. Таким образом, если контекст подписанного узла будет изменен (он будет перемещен в пределах этого же дерева или перемещен в другое xml-дерево), подпись может стать недействительна, если пространства имен, объявленные выше по иерархии, изменятся. В таких случаях нужно использовать метод канонизации "Exclusive Canonical XML" (http://www.w3.org/2001/10/xml-exc-c14n#), который не учитывает объявленные выше по иерархии пространства имен (кроме пространств имен, которые действительно используются внутри подписываемого поддерева, но объявлены выше по иерархии). В C# изменение метода канонизации делается указанием:

signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NWithCommentsTransform;
XmlDsigExcC14NWithCommentsTransform transform = new XmlDsigExcC14NWithCommentsTransform();
reference.AddTransform(transform );

В этом примере signedXml - объект SignedXml, представляющий подписываемую XML, reference - объект Reference, указывающий на подписываемый узел (для которого выполняется signedXml.AddReference(reference); перед вычислением подписи). В примере использован стандарт   "Exclusive Canonical XML with comments" (http://www.w3.org/2001/10/xml-exc-c14n#WithComments), корректно работающий с комментариями в XML.

Orbeon: создание XML-элемента с пространством имен с помощью XPath

Задача: 

Создать элемент с пространством имен, описанным в этом же элементе (установить xmlns как атрибут, передав его вторым параметром функции xxforms:element, нельзя - Orbeon просто проигнорирует атрибуты с именем xmlns или из пространства имен xmlns). Например:
<foo:mytag xmlns:foo='some-name-space'/>

Решение:

xxforms:element(QName('some-name-space'),'foo:mytag'))

или, если, к примеру, нужно взять namespace другого узла:

xxforms:element(QName(namespace-uri(/path/to/other/node),'foo:mytag')

Правда, такое создание элемента связано со следующей проблемой (вернее, скорее всего, багом орбеона): при использовании пространства имен по-умолчанию (т.е. передавая в QName имя элемента без пространства имен), элемент не создается. Если пытаться выполнить эту операцию в XForms Inspector, вылетает "java.lang.StringIndexOutOfBoundsException: String index out of range: -1", при использовании этого XPath в других местах он также приводит к некорректному поведению орбеона. Другого способа создавать элементы с пространством имен по-умолчанию я не нашел, разве что описывать элемент строкой, после чего парсить её с помощью saxon:parse:

saxon:parse('<mytag xmlns=''some-name-space''/>')
В таком случае, однако, нельзя одновременно с созданием элемента добавить ему потомков без их сериализации в строку, как это позволяет сделать xxforms:element.

JavaScript: преобразование Document в String

Реализации различаются для IE и Firefox, насчет работоспособности в других браузерах - не пробовал:

function XMLtoString(elem)
{ var serialized; try {
// XMLSerializer exists in current Mozilla browsers
serializer = new XMLSerializer();
serialized = serializer.serializeToString(elem);
}
catch (e) {
// Internet Explorer has a different approach to serializing XML
serialized = elem.xml;
} return serialized;
}

Источник: http://www.sencha.com/forum/showthread.php?34553-Convert-DOM-XML-Document-to-string.

четверг, 1 декабря 2011 г.

Сборка C# из командной строки

Для сборки cs-файлов без использования Visual Studio имеется утилита csc.exe, расположенная в директории вроде C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe. Пример вызова:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Data.dll /reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll /reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Security.dll /reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll  /target:library project.cs

xpath: получение текста узла

Тривиально, но всё же:
/path/to/text/node/text()