private void GatherDataItemsFromXElement(DataSet data,
XmlNode sourceElement, // can be the whole sourceDom or just a page
HashSet<Tuple<string, string>> itemsToDelete = null)
{
string elementName = "*";
try
{
string query = String.Format(".//{0}[(@data-book or @data-library or @data-collection or @data-book-attributes) and not(contains(@class,'bloom-writeOnly'))]", elementName);
XmlNodeList nodesOfInterest = sourceElement.SafeSelectNodes(query);
foreach (XmlElement node in nodesOfInterest)
{
bool isCollectionValue = false;
string key = node.GetAttribute("data-book").Trim();
if (key == String.Empty)
{
key = node.GetAttribute("data-book-attributes").Trim();
if (key != String.Empty)
{
GatherAttributes(data, node, key);
continue;
}
key = node.GetAttribute("data-collection").Trim();
if (key == String.Empty)
{
key = node.GetAttribute("data-library").Trim(); //the old (pre-version 1) name of collections was 'library'
}
isCollectionValue = true;
}
string value;
if (HtmlDom.IsImgOrSomethingWithBackgroundImage(node))
{
value = HtmlDom.GetImageElementUrl(new ElementProxy(node)).UrlEncoded;
KeysOfVariablesThatAreUrlEncoded.Add(key);
}
else
{
var node1 = node.CloneNode(true); // so we can remove labels without modifying node
// Datadiv content should be node content without labels. The labels are not really part
// of the content we want to replicate, they are just information for the user, and
// specific to one context. Also, including them causes them to get repeated in each location;
// SetInnerXmlPreservingLabel() assumes data set content does not include label elements.
var labels = node1.SafeSelectNodes(".//label").Cast<XmlElement>().ToList();
foreach (var label in labels)
label.ParentNode.RemoveChild(label);
value = node1.InnerXml.Trim(); //may contain formatting
if(KeysOfVariablesThatAreUrlEncoded.Contains(key))
{
value = UrlPathString.CreateFromHtmlXmlEncodedString(value).UrlEncoded;
}
}
string lang = node.GetOptionalStringAttribute("lang", "*");
if (lang == "") //the above doesn't stop a "" from getting through
lang = "*";
if (lang == "{V}")
lang = _collectionSettings.Language1Iso639Code;
if(lang == "{N1}")
lang = _collectionSettings.Language2Iso639Code;
if(lang == "{N2}")
lang = _collectionSettings.Language3Iso639Code;
if (string.IsNullOrEmpty(value))
{
// This is a value we may want to delete
if (itemsToDelete != null)
itemsToDelete.Add(Tuple.Create(key, lang));
}
else if (!value.StartsWith("{"))
//ignore placeholder stuff like "{Book Title}"; that's not a value we want to collect
{
if ((elementName.ToLowerInvariant() == "textarea" || elementName.ToLowerInvariant() == "input" ||
node.GetOptionalStringAttribute("contenteditable", "false") == "true") &&
(lang == "V" || lang == "N1" || lang == "N2"))
{
throw new ApplicationException(
"Editable element (e.g. TextArea) should not have placeholder @lang attributes (V,N1,N2)\r\n\r\n" +
node.OuterXml);
}
//if we don't have a value for this variable and this language, add it
if (!data.TextVariables.ContainsKey(key))
{
var t = new MultiTextBase();
t.SetAlternative(lang, value);
data.TextVariables.Add(key, new NamedMutliLingualValue(t, isCollectionValue));
}
else if (!data.TextVariables[key].TextAlternatives.ContainsAlternative(lang))
{
MultiTextBase t = data.TextVariables[key].TextAlternatives;
t.SetAlternative(lang, value);
}
}
if (KeysOfVariablesThatAreUrlEncoded.Contains(key))
{
Debug.Assert(!value.Contains("&"), "In memory, all image urls should be encoded such that & is just &.");
}
}
}
catch (Exception error)
{
throw new ApplicationException(
"Error in GatherDataItemsFromDom(," + elementName + "). RawDom was:\r\n" + sourceElement.OuterXml,
error);
}
}