Saving XML Root Attributes
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3

Thread: Saving XML Root Attributes

  1. #1
    Join Date
    Jul 2012
    Posts
    8

    Saving XML Root Attributes

    I've been working on a CMS built using AJAX and PHP. Pretty much it saves everything to XML files. Everything is working perfectly except getting the root node's attributes to save. These are never brought in to edit, I don't want these visible in the CMS. So what happens when I save, all of the root node attributes get removed. I've gone over this so much that I can't figure out what's causing this. So I thought another set of eyes my help.

    The saving function is called saveXml() and is located at the bottom

  2. #2
    Join Date
    Jul 2012
    Posts
    8

    Re: Saving XML Root Attributes

    Code:
    var menuXmlData;
    var pageXmlData;
    var pageXmlRules;
    var xmlFileToEdit;
    
    jQuery(document).ready(function($)
    {
    	resetPage();
    });
    
    function resetPage()
    {
    	// get our xml file/data
    	$.ajax({
    		type:'GET',
    		async: false,
    		url:'../MenuSystem.xml'+'?bc='+Math.floor(Math.random()+9999999),
    		success:function(xmlDoc){ menuXmlData = xmlDoc.documentElement; },
    		dataType:'xml'
    	});
    	
    	// if there's a GET var telling us which page to edit, edit that page
    	// otherwise output a menu of pages to edit
    	var editVar = getQueryVar('page');
    	if (editVar == '' || editVar == null)
    		fillInMenuOfPages();
    	else
    		startPageEditor(editVar);
    }
    
    function getQueryVar(nm)
    {
    	var results = RegExp('[?|&]'+nm+'=?(.*?)(&|$)').exec(window.location.search);
    	return results==null ? null : decodeURIComponent(results[1]);
    }
    
    function fillInMenuOfPages()
    {
    	$('.top-description').text('Choose a page/section below to edit:');
    	$('.save-btn').css('display','none');
    	var pages = menuXmlData.getElementsByTagName('page'), i, ii = pages.length, nd, isLink, noClick;
    
    	$('#main-editor').append('<div class="page-edit-link"><a href="edit-page-content.php?page=accordion">HOME BANNER</a></div>');
    
    	for (i = 0; i < ii; i++)
    	{
    		nd = pages[i];
    		isLink = nd.getAttribute('isLink');
    		noClick = nd.getAttribute('noClick');
    		if (isLink == 'true' || noClick == 'true')
    			continue;
    		
    		$('#main-editor').append(
    			$('<div class="page-edit-link"><a href="edit-page-content.php?page='+nd.getElementsByTagName('hash')[0].textContent.substr(1)+'">'+
    				nd.getElementsByTagName('label')[0].textContent+
    			'</a></div>')
    		);
    	}
    	$('#main-editor').append($('<div style="clear:both"></div>'));
    	$('.to-top-btn').css('visibility', 'hidden');
    	
    	$('.to-top-btn').css('visibility', 'visible');
    }
    
    var isNoRules = false;
    function startPageEditor(editVar)
    {
    	editVar = '#'+editVar;
    	var pages = menuXmlData.getElementsByTagName('page'), i, ii = pages.length, moduleFile;
    	var siteUrl = document.URL.substr(0,document.URL.lastIndexOf('/admin')+1);
    
    	//first page, accordion
    	var pageHashHtml = '';
    	var pageUrlHtml = '';
    	//var xmlFileToEdit = 'xml/accordion.xml';
    	// moduleFile = 'modules/accordion.swf';
    	var noMenu = 'true';
    
    	for (i = 0; i < ii; i++)
    	{
    		
    		if (pages[i].getElementsByTagName('hash')[0].textContent == editVar)
    		{
    			//xmlFileToEdit = pages[i].getElementsByTagName('xml')[0].textContent;
    			moduleFile = pages[i].getElementsByTagName('swf')[0].textContent;
    			pageHashHtml = siteUrl+pages[i].getElementsByTagName('hash')[0].textContent;
    			pageUrlHtml = siteUrl+pages[i].getElementsByTagName('path')[0].textContent;
    			noMenu = 'false';
    
    			if (pageHashHtml == "#fleet" || pageHashHtml == "#fuel" || pageHashHtml == "#service-area" || pageHashHtml == "#automotive" || pageHashHtml == "#home") {
    				xmlFileToEdit = 'xml/'+pageHashHtml.replace("#", "")+'.xml';
    			} else {
    				xmlFileToEdit = pages[i].getElementsByTagName('xml')[0].textContent;
    			}
    		} else if (editVar == "#accordion") {
    			xmlFileToEdit ='xml/accordion.xml';
    			moduleFile = 'modules/accordion.swf';
    			pageHashHtml = '';
    			pageUrlHtml = '';
    		}
    	}
    	
    	if (xmlFileToEdit === undefined)
    		{ $('.top-description').text("Invalid page specified to edit."); return; }
    	
    	$.ajax({
    		type:'GET',
    		async: false,
    		url:'../'+xmlFileToEdit+'?bc='+Math.floor(Math.random()+9999999),
    		success:function(xmlDoc){ pageXmlData = xmlDoc.documentElement; },
    		dataType:'xml'
    	});
    	
    	var slashIndex = moduleFile.lastIndexOf('/');
    	var dotIndex = moduleFile.lastIndexOf('.');
    	if (dotIndex < 0) dotIndex = moduleFile.length;
    	
    	// check to see if this page to edit is a SWF scroll modules that load other SWF modules
    	if (pageHashHtml == "#fleet" || pageHashHtml == "#fuel" || pageHashHtml == "#service-area" || pageHashHtml == "#automotive" || pageHashHtml == "#home") {
    		var rulesFile = 'scripts/xml-editor-rules-'+pageHashHtml.replace("#", "")+'.xml';
    	} else {
    		var rulesFile = 'scripts/xml-editor-rules-'+moduleFile.substring(slashIndex+1, dotIndex)+'.xml';
    	}
    
    	$.ajax({
    		type:'GET',
    		async: false,
    		url:rulesFile+'?bc='+Math.floor(Math.random()+9999999),
    		error:function(){ isNoRules = true; },
    		success:function(xmlDoc){ pageXmlRules = xmlDoc.documentElement; },
    		dataType:'xml'
    	});
    	
    	if (!isNoRules)
    	{
    		var htmlData = convertXmlToHtml(pageXmlData, 1);
    		$('#main-editor').html('<div id="drag-indic"></div>'+htmlData);
    		addJavascriptActions();
    		
    		$(document).unbind('mouseup').bind('mouseup', dragEnd);
    		$(document).unbind('mousemove').bind('mousemove', dragHappening);
    		
    		if (noMenu == 'true') {
    			$('#page-info').html('<p class="page-loc">Editing content of page: <a href="../index.php" target="_blank">Home Banner'+rulesFile+'</a></p>');
    		} else {
    			$('#page-info').html('<p class="page-loc">Editing content of page: <a href="../'+pageUrlHtml+'" target="_blank">'+pageHashHtml+'</a> '+xmlFileToEdit+'</p>');
    		}
    
    	}
    	else
    	{
    		var xmlText = '';
    		$.ajax({
    			type:'GET',
    			async: false,
    			url:'../'+xmlFileToEdit+'?bc='+Math.floor(Math.random()+9999999),
    			success:function(xmlT){ xmlText = xmlT; },
    			dataType:'text'
    		});
    		
    		// adding iframe to acceptable tags for html editor
    		WYMeditor.XhtmlLexer.prototype.addTokens = function() { this.addEntryPattern("</?iframe", 'Text', 'Text');this.addExitPattern(">", 'Text');this.addCommentTokens('Text');this.addScriptTokens('Text');this.addCssTokens('Text');this.addTagTokens('Text');};
    		$('#main-editor').html('<textarea class="wysiwyg-editor">'+xmlText+'</textarea>');
    		$('.wysiwyg-editor').wymeditor({
    			toolsItems: [
    				{'name': 'Bold', 'title':  'Strong', 'css':  'wym_tools_strong'},
    				{'name': 'Italic', 'title': 'Emphasis', 'css': 'wym_tools_emphasis'},
    				{'name': 'CreateLink', 'title': 'Link', 'css': 'wym_tools_link'},
    				{'name': 'Unlink', 'title': 'Unlink', 'css': 'wym_tools_unlink'},
    				{'name': 'InsertOrderedList', 'title': 'Ordered_List', 'css': 'wym_tools_ordered_list'},
    				{'name': 'InsertUnorderedList', 'title': 'Unordered_List', 'css': 'wym_tools_unordered_list'},
    				{'name': 'Paste', 'title': 'Paste_From_Word', 'css': 'wym_tools_paste'},
    				{'name': 'Undo', 'title': 'Undo', 'css': 'wym_tools_undo'},
    				{'name': 'Redo', 'title': 'Redo', 'css': 'wym_tools_redo'},
    				{'name': 'ToggleHtml', 'title': 'HTML', 'css': 'wym_tools_html'}
    			]
    		});
    		$('.wym_containers h2').text('Formatting');
    		$('.wym_html_val').keydown(function(e){ // make tab work in html source view
    			if (e.keyCode == 9)
    				{var myValue = "\t";var startPos = this.selectionStart;var endPos = this.selectionEnd;var scrollTop = this.scrollTop;this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos,this.value.length);this.focus();this.selectionStart = startPos + myValue.length;this.selectionEnd = startPos + myValue.length;this.scrollTop = scrollTop;e.preventDefault();}
    		});
    		$('#main-editor').fadeOut(0).fadeIn(500);
    		
    		$('#page-info').html('<p class="page-loc">Editing HTML content of page: <a href="../'+pageUrlHtml+'" target="_blank">'+pageUrlHtml+'</a></p>');
    		$('#page-info').append($('<p class="page-details">This is a custom swf or blank swf page, so please fill in HTML backup content for mobiles and search engines.</p>'));
    	}
    	
    	$('.to-top-btn').css('visibility', 'visible');
    }
    
    function convertXmlToHtml(node, lvl)
    {
    	//if (isNaN(lvl)) lvl = 1; // now always sends the 1 for first call
    	var returnVal = '';
    	
    	// jquery parsing
    	var childNode, childNodeName, isText;
    	$(node).children().each(function(){
    		childNode = $(this);
    		isText = childNode.children().length < 1;
    		childNodeName = childNode[0].nodeName;
    		
    		returnVal += '<div class="node lvl-'+lvl+'"><div class="node-bg"></div><p class="node-label">'+
    			childNodeName+
    			'</p>'+
    				(isText ? '' : '<a class="open-close-btn">open/close</a>') +
    			'<span class="node-name">'+
    			childNodeName+
    			'</span><span class="node-attributes">'+
    				getAttributesString(childNode[0]) +
    			'</span><span class="node-text">'+
    			(isText ? encodeURI(childNode.text()) : '')+
    			'</span><span class="editor-rules">'+
    			getRulesArray(childNode[0], true).join('')+
    			'</span><div class="node-children">'+
    				(isText ? '' : convertXmlToHtml(childNode,lvl+1)) +
    			'</div></div>';
    	});
    	
    	return returnVal;
    }
    // in the flash fast parser this is duplicated
    function getAttributesString(node)
    {
    	var returnVal = '';
    	var attributes = node.attributes;
    	
    	if (attributes==undefined || attributes.length==0)
    		return '';
    	
    	var i = 0, ii = attributes.length, attr;
    	for (i = 0; i < ii; i++)
    	{
    		attr = attributes[i];
    		returnVal += '<span class="attribute">'+
    			'<span class="attribute-name">'+attr.name+'</span>'+
    			'<span class="attribute-value">'+attr.value+'</span>'+
    		'</span>';
    	}
    	
    	return returnVal;
    }
    function addJavascriptActions()
    {
    	$mainEditor = $('#main-editor');
    	
    	// by default, close all children nodes, start with just the root child nodes showing
    	$mainEditor.find('.node-children').css('opacity',0).slideUp(1);
    	$mainEditor.find('.open-close-btn').css('opacity', 0.6).bind('click',function(){
    		if (!isSlidingNow) // only go if not already sliding something!!!!!
    		{
    			isSlidingNow = true;
    			$(this).toggleClass('open');
    			var isOpen = $(this).hasClass('open'), time = 500;
    			if (isOpen)
    				slideOpen($(this).parent().children('.node-children'));
    			else
    				slideClose($(this).parent().children('.node-children'));
    		}
    	}).bind('mouseover', function(){ $(this).css('opacity',1); }).bind('mouseout', function(){ $(this).css('opacity',0.6); });
    	
    	// open things with the rule to start out opened
    	$mainEditor.find('action:contains(begin-open)').each(function(){
    		var $par = $(this).parent().parent().parent();
    		$par.children('.node-children').css('opacity',1).slideDown(1);
    		$par.children('.open-close-btn').addClass('open');
    	});
    	
    	// give custom labels to items with those defined in rules
    	$mainEditor.find('rule label').each(function(){
    		var $par = $(this).parent().parent().parent();
    		$par.children('.node-label').text( $(this).text() );
    	});
    	
    	// give editable input box to nodes with that in rules
    	$mainEditor.find('action:contains(show-one-line-editor)').each(function(){
    		var $par = $(this).parent().parent().parent();
    		var spellcheck = $par.children('.editor-rules').children('rule').children('action:contains(use-spellcheck)').get(0)==undefined ? 'false' : 'true';
    		var val = decodeURI($par.children('.node-text').text());
    		$input = $('<input class="single-line-xml-editor" type="text" value="'+val+'" placeholder="blank" spellcheck="'+spellcheck+'" />');
    		$par.children('.node-label').after($input);
    		$input.bind('change', function(){
    			$(this).parent().children('.node-text').text( encodeURI($(this).val()) );
    			changesNotSaved = true;
    		});
    	});
    	
    	// make draggable the items that the rules say should be draggable
    	$mainEditor.find('action:contains(allow-dragging)').parent().parent().parent().bind('mousedown', dragStart);
    	
    	// add in help buttons
    	$mainEditor.find('help').each(function(){
    		var $par = $(this).parent().parent().parent();
    		$par.children('.node-children').before($('<div class="help-btn" style="top:-41px;margin-right:10px;"><p>'+$(this).text()+'</p></div>'));
    	});
    	
    	// add attribute button to nodes needing ability to edit attributes
    	$mainEditor.find('action:contains(allow-attribute-editing)').each(function(){
    		var $par = $(this).parent().parent().parent();
    		var $newElem = $('<p class="node-action-link"><a title="Edit this node\'s attributes." href="javascript:;">attributes</a></p>');
    		$par.children('.node-children').before($newElem);
    		$newElem.children('a').bind('click', function(){
    			var $par = $(this).parent().parent();
    			openAttributeEditor( $par.children('.node-attributes') );
    		});
    	});
    	
    	// add duplication button to nodes needing ability to duplicate
    	$mainEditor.find('action:contains(allow-duplication)').each(function(){
    		var $par = $(this).parent().parent().parent();
    		var $newElem = $('<p class="node-action-link"><a title="Create and add a copy of this node." href="javascript:;">duplicate</a></p>');
    		$par.children('.node-children').before($newElem);
    		$newElem.children('a').bind('click', function(){
    			var $fake = $('<div style="height:0px;"></div>');
    			var $orig  = $(this).parent().parent();
    			var $clone = $orig.clone(true,true);
    			$orig.before($fake);
    			$fake.animate({height:53}, {complete:function(){
    				$fake.remove();
    				$orig.before($clone);
    				$clone.css({top:'50px',opacity:.1}).animate({top:0,opacity:1});
    			}});
    			changesNotSaved = true;
    		});
    	});
    	
    	// add deletion button to nodes needing ability to delete
    	$mainEditor.find('action:contains(allow-deletion)').each(function(){
    		var $par = $(this).parent().parent().parent();
    		var $newElem = $('<p class="node-action-link"><a title="Delete this entire node." href="javascript:;">delete</a></p>');
    		$par.children('.node-children').before($newElem);
    		$newElem.children('a').bind('click', function(){
    			var $orig  = $(this).parent().parent();
    			var nodeName = $orig.children('.node-name').text();
    			if ($orig.parent().children('.node').children('.node-name:contains('+nodeName+')').length <= 1)
    				{ alert("You cannot delete the last node of a set, please edit it to your needs rather than delete it!"); return; }
    			var $fake = $('<div style="height:'+($orig.height()+9)+'px;"></div>');
    			$orig.fadeOut('normal', function(){
    				$orig.before($fake);
    				$orig.remove();
    				$fake.animate({height:0}, {complete:function(){
    					$fake.remove();
    				}});
    			});
    			changesNotSaved = true;
    		});
    	});
    	
    	// add ability to select a file from the file manager
    	$mainEditor.find('action:contains(allow-file-selection)').each(function(){
    		var $par = $(this).parent().parent().parent();
    		var $newElem = $('<p class="node-action-link"><a title="Upload or select a file from the file manager." href="javascript:;">upload/select new</a></p>');
    		$par.children('.node-children').before($newElem);
    		$newElem.children('a').bind('click', function(){
    			var $par = $(this).parent().parent();
    			var $textNode = $par.children('.node-text');
    			openFileManager($textNode.text(), function(newFNm){
    				$textNode.text(newFNm);
    				$par.children('.single-line-xml-editor').val(newFNm);
    			}, true);
    		});
    	});
    	
    	// add large text editor button to nodes needing ability to edit larger text content
    	$mainEditor.find('action:contains(show-text-editor)').each(function(){
    		var $par = $(this).parent().parent().parent();
    		var $newElem = $('<p class="node-text-edit-link"><a title="Open the text editor to edit this content." href="javascript:;">edit</a></p>');
    		$par.children('.node-children').before($newElem);
    		$newElem.children('a').bind('click', function(){
    			var $par  = $(this).parent().parent();
    			var $textNode = $par.children('.node-text');
    			openTextEditor($textNode);
    		});
    	});
    }
    
    function getRulesArray(n, asStr)
    {
    	// if no rules, give empty array
    	if (pageXmlRules == undefined) return [];
    	
    	// figure out the appropriate path string for this node
    	var path = n.nodeName, nodeP = n;
    	while(true)
    	{
    		nodeP = nodeP.parentNode;
    		
    		if (String(nodeP.parentNode) == '[object Document]' // webkit check for if at root
    			|| (nodeP.parentNode && nodeP.parentNode.nodeName == '#document') // ff check for if at root
    			|| nodeP == undefined // generic check
    		)
    			{ path = 'root.'+path; break; }
    		path = nodeP.nodeName + '.' + path;
    	}
    	
    	// jquery way
    	var rulesArr = [];
    	$(pageXmlRules).children('rule[pathMatch="'+path+'"]').each(function(){
    		rulesArr.push(asStr ? getXmlString($(this).get(0)) : $(this).get(0));
    	});
    	
    	return rulesArr;
    }
    
    function convertHtmlToXml($par, lvl)
    {
    	if (isNaN(lvl)) lvl = 1;
    	var returnVal = '';
    	
    	var $this, nodeName, txtContent, doCdata, tabStr, childContent;
    	$par.children('.node').each(function(){
    		$this = $(this);
    		nodeName = $this.children('.node-name').text();
    		tabStr = tabBy(lvl);
    		txtContent = $.trim(decodeURI($this.children('.node-text').text()));
    		doCdata = $this.children('.editor-rules').children('rule').children('action:contains(save-cdata)').length > 0;
    		if (txtContent != '' && doCdata) txtContent = '<![CDATA[' + txtContent + ']]>';
    		childContent = convertHtmlToXml($this.children('.node-children'),lvl+1);
    		returnVal += '\n'+tabStr+'<'+nodeName+attributesToString($this)+'>'+
    			txtContent +
    			childContent +
    		(txtContent != '' || $.trim(childContent) == '' ? '' : '\n'+tabStr)+'</'+nodeName+'>';
    	});
    	
    	return returnVal;
    }
    function attributesToString($node)
    {
    	var retVal = ''
    	var $attr = $node.children('.node-attributes');
    	$attr.children('.attribute').each(function(){
    		retVal += ' ' + $(this).children('.attribute-name').text() + '="' + $(this).children('.attribute-value').text().split('"').join('&quot;').split('&').join('&amp;') + '"';
    	});
    	return retVal;
    }
    function tabBy(n)
    {
    	var retVal = '';
    	var i, ii = n;
    	for (i=0; i<ii; i++)
    		retVal += '\t';
    	return retVal;
    }
    
    function saveXml()
    {
    	var xmlStr = '';
    	if (!isNoRules)
    	{
    		var rootNodeName = pageXmlData.nodeName;
    		xmlStr = '<?xml version="1.0" encoding="utf-8"?>\n<'+rootNodeName+'>'+convertHtmlToXml($('#main-editor'))+'\n</'+rootNodeName+'>';
    		// xmlStr = vkbeautify.xml(xmlStr); // vkbeautify handles the cdata like crap, gonna have to make it pretty in the convertHtmlToXml function
    	}
    	else
    	{
    		var index = $('.wysiwyg-editor').data('wym_index');
    		xmlStr = $.wymeditors(index).xhtml();
    	}
    	
    	// clear the page while resaving
    	$('#main-editor').html('<div class="page-waiting-busy"></div>');
    	$('.to-top-btn').css('visibility', 'hidden');
    	
    	$.post('scripts/save-page-edit-xml.php', {data:xmlStr, fname:xmlFileToEdit}, function(status)
    	{
    		if (status == 'auth-failure')
    			alert('Your log-in credentials have expired, please refresh the page and log-in again.');
    		else if (status != 'success') 
    			alert('Save failed. Please check that your file permissions are set to allow writing and that your host allows basic PHP read/write functions.\n\nThe following is a php error messages for debug purposes, ignore it:\n'+status);
    		else
    			setTimeout(function(){$('.save-btn').removeClass('working');$('.save-indic').fadeIn(150).delay(1200).fadeOut(300);}, 1000);
    		
    		resetPage();
    		changesNotSaved = false;
    	},
    	'text');
    }

  3. #3
    Join Date
    Jul 2012
    Posts
    8

    Re: Saving XML Root Attributes

    To view the code better --> http://pastie.org/5055988

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center