#javascript #xml #json #parsing #text-parsing
#javascript #xml #json #Синтаксический анализ #синтаксический анализ текста
Вопрос:
Я создал функцию для этого.
var text="adsf [name]Victor[/name] dummytext [name]Elliot[/name] asdf [name]Jake[/name] asdf [foo]bar[/foo]";
alert( readTags(text,'name') ); //Victor,Elliot,Jake
alert( readTags(text,'foo') ); //bar
но теперь мне нравится реализовывать функцию, которая получает строку, подобную этой
[person]
[name]jake[/name]
[age]12[/age]
[/person]
и вернуть объект, подобный этому
var object={};
object['person']={};
object['name']='jake';
object['age']='12';
return(object);
но я не знаю, как выполнить цикл по тексту. Как работать с начальными и конечными тегами?
Нравится
[tag] [tag]value[/tag] [/tag]
Я думал найти начальный тег слева и конечный тег справа, используя indexOf('[tag]')
и lastindexOf('[/tag]')
но в этой ситуации не работает
[tag]value[/tag] [tag]value[/tag]
это предыдущая функция
function readTags(str,property){
var beginTag='[' property ']';
var endTag='[/' property ']';
var values=new Array(0);
while(str.indexOf(beginTag)!=-1){
values[values.length]=strBetween(str,beginTag,endTag);
str=str.substring(str.indexOf(endTag) endTag.length);
}
return(values);
}
function strBetween(string,strBegin,strEnd){ //StrBetween("abcdef","b","e") //return "cd"
var posBegin, posEnd;
posBegin=string.indexOf(strBegin);
string=string.substring(posBegin strBegin.length);
posEnd=string.indexOf(strEnd);
string=string.substring(0,posEnd);
if ((posBegin==-1)||(posEnd==-1)){
return(null);
}else{
return(string);
}
}
Комментарии:
1. Не делайте этого. Вместо этого используйте JSON .
2. @PointedEars Я использую блоги для размещения контента, который может быть захвачен подобными роботами, почти все они добавляют мусор в JSON или не допускают теги XML или <>
Ответ №1:
Если у вас нет веской причины не использовать JSON, не делайте этого. JSON очень хорошо справляется со всеми этими проблемами и может довольно легко перемещаться с сервера на клиент и наоборот.
Но поскольку это кажется забавным, я попробую и посмотрю, смогу ли я придумать ответ.
Поскольку ваша структура напоминает XML, просто замените скобки на <
и >
и проанализируйте его как XML:
text = text.replace('[', '<').replace(']', '>');
if (typeof DOMParser != "undefined") {
var parser = new DOMParser();
var xml = parser.parseFromString(text, 'text/xml');
} else {
var xml = new ActiveXObject('Microsoft.XMLDOM');
xml.async = 'false';
xml.loadXML(text);
}
Теперь xml
содержит DOMDocument
, который вы можете разобрать:
xml.getElementsByTagName('person').childnodes;
Попробуйте этот, возможно, работающий код (не тестировался):
function createObject(element) {
var object = {};
if (element.childNodes.length > 0) {
for (child in element.childnodes) {
object[element.tagName] = createObject(child);
}
return object;
} else {
return element.nodeValue;
}
}
Комментарии:
1. умное решение! это кроссбраузерный? теперь я думаю, что могу использовать
getElementsByTagName("*")
для зацикливания всех элементов и генерации объекта. Я прав?2. Вторая часть
if
обрабатывает IE, который является проблемой в каждом случае. Что касается второй части, конечно. Я бы лично придерживалсяchildnodes
иtagName
для итерации. Это упростит вашу задачу.3. (на самом деле, это была моя следующая идея) Не используйте
window
здесь; используйтеthis
, если необходимо, но лучшеif (typeof DOMParser != "undefined")
. Объявляйтеtext
,parser
xml
и т.д. Переменные с помощьюvar
. ВозвращаетNodeList
, так должно бытьgetElementsByTagName("person")[0]
. Должно бытьchildNodes
(чувствительно к регистру). DOMParser на данный момент довольно кросбраузерен. Для IE / MSHTML у вас есть вторая ветвь; однако требуется включенная поддержка ActiveX. Передача «*» вернет список узлов всех элементов. Но он будет плоским, поэтому вы не сможете создать из него свой объект. Вам нужно пройти по дереву. Здесь может помочь E4X.4. @PointedEars: Спасибо за советы. Я включил все, что мог.
5. @PointedEars плоский список будет проблемой, но я думаю, что могу использовать функцию, которую я написал в прошлом, для перемещения по дереву, используя рекурсию, чтобы углубиться в «многомерный массив», но я понятия не имею, сработает ли это.
Ответ №2:
Я подумал, что это было бы интересно сделать без стороннего анализатора, поэтому я создал простой:
function parse(code)
{
var obj = {},
cur = obj,
stack = [];
code.replace(/[([^]] )]|([^[]*)/g, function (match, tagName, text) {
if (tagName)
{
if (tagName.charAt(0) == "/")
{
/* end tag */
cur = stack.pop();
}
else
{
/* start tag */
stack.push(cur);
cur = cur[tagName] = {};
}
}
else
{
cur["#text"] = text;
}
});
return obj;
}
var obj = parse(text);
Ответ №3:
JSON <=> XMLhttp://code.google.com/p/x2js