Можно ли как-то связать хмл парсер с html парсером?
Есть хмл файлы, которые внутри содержат html блоки. Хотелось бы, что-бы на этом html появились html quick fixes.
Здравствуйте, ifle, Вы писали:
I>Можно ли как-то связать хмл парсер с html парсером? I>Есть хмл файлы, которые внутри содержат html блоки. Хотелось бы, что-бы на этом html появились html quick fixes.
Можно создать injected-psi для этих блоков с языком html. Нужно завести свой SolutionComponent, отнаследовав его от IndependentInjectedPsiProvider, и там описать, что вы хотите инжектить html в ноды, удовлетворяющие нужному критерию.
Примером того, как сделать подобное, может служить JsDocInjectedPsiProvider.
Re[2]: [Resharper SDK] Распарсить html сохранённый в xml.
Здравствуйте, zhuravlik26, Вы писали:
Z>Можно создать injected-psi для этих блоков с языком html. Нужно завести свой SolutionComponent, отнаследовав его от IndependentInjectedPsiProvider, и там описать, что вы хотите инжектить html в ноды, удовлетворяющие нужному критерию. Z>Примером того, как сделать подобное, может служить JsDocInjectedPsiProvider.
Спасибо, то что нужно. Что должны делать функции CanBeGeneratedNode, CanBeOriginalNode?
Re[3]: [Resharper SDK] Распарсить html сохранённый в xml.
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, zhuravlik26, Вы писали:
Z>>Можно создать injected-psi для этих блоков с языком html. Нужно завести свой SolutionComponent, отнаследовав его от IndependentInjectedPsiProvider, и там описать, что вы хотите инжектить html в ноды, удовлетворяющие нужному критерию. Z>>Примером того, как сделать подобное, может служить JsDocInjectedPsiProvider.
I>Спасибо, то что нужно. Что должны делать функции CanBeGeneratedNode, CanBeOriginalNode?
CanBeGeneratedNode возвращает, является ли переданная ему нода нодой верхнего уровня заинжекченного языка. В вашем случае оно должно быть в стиле "return node is IHtmlFile;"
CanBeOriginalNode возвращает, является ли переданная ему нода той нодой, куда вы повесили инжект. В вашем случае это какая-то xml-нода.
Re[4]: [Resharper SDK] Распарсить html сохранённый в xml.
Здравствуйте, zhuravlik26, Вы писали:
Z>Здравствуйте, ifle, Вы писали:
I>>Здравствуйте, zhuravlik26, Вы писали:
Z>>>Можно создать injected-psi для этих блоков с языком html. Нужно завести свой SolutionComponent, отнаследовав его от IndependentInjectedPsiProvider, и там описать, что вы хотите инжектить html в ноды, удовлетворяющие нужному критерию. Z>>>Примером того, как сделать подобное, может служить JsDocInjectedPsiProvider.
I>>Спасибо, то что нужно. Что должны делать функции CanBeGeneratedNode, CanBeOriginalNode?
Z>CanBeGeneratedNode возвращает, является ли переданная ему нода нодой верхнего уровня заинжекченного языка. В вашем случае оно должно быть в стиле "return node is IHtmlFile;"
Z>CanBeOriginalNode возвращает, является ли переданная ему нода той нодой, куда вы повесили инжект. В вашем случае это какая-то xml-нода.
Заинжекченный ноде у меня парсится как HTML. Вот только с оффсетами не совсем в порядке.
Вот пример, что получается.
Хайглайнинг промахнулся, должен был пометить CELLSPACING=0.
Дело в том, что html не храниться в одной ноде, он храниться как текст xml тага. т.е текст по частям находиться в коллекции xmlTag.InnerTextTokens.
Также есть дополнительные смещения из-за ескеппинга html.
Приемр моего кода
public override IInjectedNodeContext CreateInjectedNodeContext(IInjectedFileContext fileContext, ITreeNode originalNode)
{
var xmlTag = (IXmlTag) originalNode;
var text = xmlTag.InnerValue;
if (string.IsNullOrEmpty(text))
return null;
StringBuffer buffer = new StringBuffer(text);
LanguageService languageService = HtmlLanguage.Instance.LanguageService();
if (languageService == null)
return null;
return CreateInjectedFileAndContext(fileContext, xmlTag, buffer, languageService, 0, text.Length);
}
Re[5]: [Resharper SDK] Распарсить html сохранённый в xml.
В вашем случае все не так просто. Скорее всего вам нужно написать еще один лексер =)
Процесс будет выглядеть так:
1) Берем исходную xml ноду <Table><TAB|LE CELLSPACIN|(0)G=0 CELLPADDIN=0 CLASS=PDS_COMBO_TABLE></TABLE></Table>
2) В injected psi провайдере переопределяем лексер, который будет лексировать ноды, после его прохода, строка должна выглядеть как-то так: <TABLE CELLSPACING=0 CELLPADDIN=0 CLASS=PDS_COMBO_TABLE></TABLE>
3) Полученную строку отдаем HTML лексеру/парсеру, с которыми он прекрасно справляется
Теперь про лексер. Пусть у нас есть HtmlLexer : ILexer
Сделаем декоратор над этим лексером MySuperLexer : ILexer, который будум использовать вместо оригинального HtmlLexer в inject psi провайдере
Сам MySuperLexer будет:
1) преобразовывать нашу строку к обычной html строке (выпиливать эскейпинг)
2) по построенной html строке создавать новый лексер и делегировать ему операции Start, Advance и т.д.
3) при запросах TokenStart и TokenEnd он должен отдавать настоящие координаты токена внутри оригинальной строки
Прототип:
public class MySuperLexer : ILexer
{
private readonly IBuffer myOriginalBuffer;
private readonly RangeTranslator myRangeTranslator;
private readonly HtmlLexer myHtmlLexer;
public ClrRegexLexer(IBuffer originalBuffer)
{
myOriginalBuffer = originalBuffer;
var htmlString = HtmlUtil.Parse(originalBuffer, out myRangeTranslator);
var buffer = new StringBuffer(htmlString);
myHtmlLexer = new HtmlLexer(buffer);
}
public void Start()
{
myHtmlLexer.Start();
}
public void Advance()
{
myHtmlLexer.Advance();
}
object ILexer.CurrentPosition
{
get { return myHtmlLexer.CurrentPosition; }
set { myHtmlLexer.CurrentPosition = value; }
}
public TokenNodeType TokenType
{
get { return myHtmlLexer.TokenType; }
}
public int TokenStart
{
get
{
return myRangeTranslator.GetSourceRange(new TextRange(myHtmlLexer.TokenStart, myHtmlLexer.TokenEnd)).StartOffset;
}
}
public int TokenEnd
{
get
{
return myRangeTranslator.GetSourceRange(myHtmlLexer.TokenEnd - 1).EndOffset;
}
}
public IBuffer Buffer
{
get { return myOriginalBuffer; }
}
}
Класс RangeTranslator предназначен для хранения информации о взаимном расположении символов в двух строках.
Метод HtmlUtil.Parse вам предстоит написать, или найти что-то похожее, я затрудняюсь сказать делали мы где-то такое или нет. Наверное делали =)
За образец можете взять ClrRegexLexer и логику из CSharpLiteralWrapper.
Аналогично вы сможете склеивать результирующую строку из кусочком, только нужно правильно ренжи сохранять =)
Если будут какие-то специфичные вопросы, пишите мне в скайп skype.stepanov.ev
Re[6]: [Resharper SDK] Распарсить html сохранённый в xml.
Здравствуйте, DragonFire, Вы писали:
DF>Класс RangeTranslator предназначен для хранения информации о взаимном расположении символов в двух строках. DF>Метод HtmlUtil.Parse вам предстоит написать, или найти что-то похожее, я затрудняюсь сказать делали мы где-то такое или нет. Наверное делали =)
DF>За образец можете взять ClrRegexLexer и логику из CSharpLiteralWrapper. DF>Аналогично вы сможете склеивать результирующую строку из кусочком, только нужно правильно ренжи сохранять =) DF>Если будут какие-то специфичные вопросы, пишите мне в скайп skype.stepanov.ev
Спасибо за такой развёрнутый ответ и предложение о помощи. Если не получиться постучусь.
В моём случае RangeTranslator ключевое звено, которого мне не хватало. С ним всё становится на свои места.
Создал свой лексер, фабрику лексера, переопределил CreateInjectedFileAndContext функцию в моём PsiProvider — валидация заработала.
Есть 2 проблемы с quick fixes:
1. Html quick fixes ничего не знают про RangeTranslator.
Предположим quick fix добавляет новый html атрибут class="centered", он добавляет его не encoded вместо class="centered"
<TABLE class="centered" ></TABLE>
но это не критично, тупо добавил дополнительный encoding
2. Есть ещё одна проблема с html сохранённым в xml. После вызова Regenerate функции в моём PsiProvider, xml меняется,
но почему-то не перезапускается html анализ.
Предположим есть нода у которой есть 2 хайтлайтинга на cellpadding и cellspecing и 2 quick fixes.
После применения первого фикса,второй хайглайтинг пропадает, только после сохранения, он снова появляется.
public override void Regenerate(IndependentInjectedNodeContext nodeContext)
{
var xmlTag = (IXmlTag)nodeContext.OriginalContextNode;
var factory = XmlElementFactory.GetInstance(nodeContext.OriginalContextNode);
var tagText = string.Format("<dummy><![CDATA[{0}]]></dummy>", XmlUtil.UnescapeXmlString(nodeContext.GeneratedNode.GetText()));
IXmlTag dummyTag = factory.CreateRootTag(tagText);
LowLevelModificationUtil.ReplaceChildRange(xmlTag.InnerXml.First(), xmlTag.InnerXml.Last(), dummyTag.InnerXml.ToArray());
}
P.S Не слишком ли накладно для каждого xml нода где есть html создавать свой IHtmlFile?
В принципе у меня файлы не большие и не очень критично, просто интересно.
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, DragonFire, Вы писали:
DF>>Если будут какие-то специфичные вопросы, пишите мне в скайп skype.stepanov.ev
I>2. Есть ещё одна проблема с html сохранённым в xml. После вызова Regenerate функции в моём PsiProvider, xml меняется, I> но почему-то не перезапускается html анализ. I> Предположим есть нода у которой есть 2 хайтлайтинга на cellpadding и cellspecing и 2 quick fixes. I> После применения первого фикса,второй хайглайтинг пропадает, только после сохранения, он снова появляется. I>
Здравствуйте, ifle, Вы писали:
I>Здравствуйте, ifle, Вы писали:
I>>Здравствуйте, DragonFire, Вы писали:
DF>>>Если будут какие-то специфичные вопросы, пишите мне в скайп skype.stepanov.ev
I>>2. Есть ещё одна проблема с html сохранённым в xml. После вызова Regenerate функции в моём PsiProvider, xml меняется, I>> но почему-то не перезапускается html анализ. I>> Предположим есть нода у которой есть 2 хайтлайтинга на cellpadding и cellspecing и 2 quick fixes. I>> После применения первого фикса,второй хайглайтинг пропадает, только после сохранения, он снова появляется. I>>
I>Связаться с DragonFire у меня не получилось. А проблема осталась
Привет еще раз. А если потайпить внутри измененной ноды анализ перезапуститься? Надо внимально посмотреть, возможно какие-то кеши не сбрасываются....
Все-таки советую связаться со мной напрямую по скайпу "skype.stepanov.ev" или почте "mail.stepanov.ev@gmail.com", быстрее решим проблемы =)
Re[9]: [Resharper SDK] Распарсить html сохранённый в xml.
Здравствуйте, DragonFire, Вы писали:
DF>Привет еще раз. А если потайпить внутри измененной ноды анализ перезапуститься? Надо внимально посмотреть, возможно какие-то кеши не сбрасываются.... DF>Все-таки советую связаться со мной напрямую по скайпу "skype.stepanov.ev" или почте "mail.stepanov.ev@gmail.com", быстрее решим проблемы =)
Всё получилось, ещё раз спасибо за помощь здесь и через skype.