0

EDIT: A bit more detailed HTML document... In short- how do I actually do the lookup and where precisely should the element.setvalue or element.value appear in the query...

Edit 2: The list of monkey id does not appear clear so I will add proper id's and add additional properties to my Lookup data object, sorry for the confusion! The reason I have used a list is bacause my datasource could be from anywhere also I have used a List object because I do not really know the proper usage of Dictionary (I am a newbie to coding hence why my question is all over the place, please bear with me)

I have an XElement which is a properly formatted HTML document, I am trying to replace only the value of a html element with a value contained in a List Object for example

<div id="pageContainer">
<p> some guy wants to <b>buy</b> a <h4><label id="monkey23">monkeyfield</label></h4> for some price that I do not have a clue about, maybe we should <i>suggest</i> a list of other monkeys he may like:
</p>
<h3>list of special monekeys you may want chappy...</h3>
<br />
<ul>
    <li><label id="monkey13">monkeyfield</label></li>
    <li><label id="monkey3">monkeyfield</label></li>
    <li><label id="animal4">animalfield</label></li>
    <li><label id="seacreature5">seacreaturefield</label></li>
    <li><label id="mamal1">mamal field</label></li>
</ul>
</div>

Note: the value "monkeyfield" is a temporary value inserted onscreen for the purpose of identifying this is a field, once the values from the data source is binded the new values should appear.

public class LookupData
{
  public string id{get;set;}
  public string value{get;set;}
  public string Type{get;set;}
  public string Url{get;set;}
}

...    
public void DataTransformerMethod()
{
 var data = new List<LookupData>();
 data.add(new LookupData{id="monkey3", value="special monkey from africa" });
 data.add(new LookupData{id="monkey13", value="old monkey from china" });
 data.add(new LookupData{id="seacreature5", value="sea monkey" });
 data.add(new LookupData{id="animal4", value="rhino" });
 data.add(new LookupData{id="mamal1", value="some mamal creature" });
 //what linq query will iterate over the document and set the values from the values
 //found in the list?

       var answer = from x in HtmlDocAsAXelement
                    where x.Attributes()
                    .Any(a=> data.AsEnumerable().Where(f=> f.Name == a.Name) );
//somehow I should use .SetValue(a.value)???

SaveTheNewXElement(answer ); //all other original data must stay in tact...

}
Haroon
  • 3,402
  • 6
  • 43
  • 74

2 Answers2

3

Well, you need to iterate over all the XElements which need changing - and set their value by just calling the Value setter:

element.Value = "newvalue";

It would be trickier if the element had multiple text nodes and you only wanted to change one of them, but as there's no other content within the element, this should be fine for you.

EDIT: After the discussion, I would do something like this:

Dictionary<string, string> replacements = data.ToDictionary(x => x.id,
                                                            x => x.value);

foreach (XElement element in HtmlDocAsAXelement.Descendants())
{
    string newValue;
    string id = (string) element.Attribute("id");
    if (id != null && replacements.TryGetValue(id, out newValue))
    {
        element.Value = newValue;
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • lol... what if it did? I only showed a samply document, note a HTML document - you know better than I do, it contains all sorts of stuff but I only want to update the fields which could be nested within a , or
    or even a

    - I will update, could you provide any code?

    – Haroon Mar 10 '11 at 10:16
  • @Haroon: It's a sensible idea to give examples of what you're *actually* trying to do... it's not a problem for the element to be nested deeply, so long as the element itself doesn't have other content. If you could give a more representative example, that would help. – Jon Skeet Mar 10 '11 at 10:18
  • I think I understood your answer, basically I was along the correct lines, the problem I have (mentioned in my question was), how do I do the lookup from the List Object, where should the correct code for .element.value should reside: .Any(a=> data.AsEnumerable().Where(f=> f.Name == a.Name) ); – Haroon Mar 10 '11 at 10:23
  • Why have you got a list to start with? A `Dictionary` would make more sense, I'd expect. It's hard to follow exactly what you're trying to do, to be honest - especially as your existing data example has two entries with the same id. – Jon Skeet Mar 10 '11 at 10:27
  • They dont: id="monkey13" id="monkey3" 3 and 13, I have a list because my object LookupData has 2 properties in the example however I have actually 5 properties which are all used however they are not relevant for the binding - I am really sorry to not add that but I did not think it mattered at all with the actual query and setting of value... – Haroon Mar 10 '11 at 10:32
  • @Haroon: Look in your sample code: id="monkey3" in both cases. You've got monkey13 in the sample HTML, but not in the code. It's really important to use accurate, representative examples. But if you want to *look up* the values by ID, you should still convert to a Dictionary. You might want to keep the list as well, but you can easily call `list.ToDictionary(value => value.id)` to perform the conversion. – Jon Skeet Mar 10 '11 at 10:34
  • sorry- I have updated, I was looking at the html code and not the c# code! All ids are unique. – Haroon Mar 10 '11 at 10:47
  • @Haroon: Your HTML example still only shows elements where a replacement is needed which are *simple* elements. What about an element which contains other elements? Would they ever need to be updated directly? For example, a paragraph which contains text and a link. – Jon Skeet Mar 10 '11 at 10:50
  • sorry, my fault for not beind so clear: Only the matching < label > < / label > will have their values replaced with the binding, everything else remains the same. So it is a simple binding. – Haroon Mar 10 '11 at 10:59
  • @Haroon: Right. In that case you can just use the XElement.Value property with no problem. – Jon Skeet Mar 10 '11 at 11:00
  • +1 Thanks Jon, greatly appreciated, this line is something I have never come across before: replacements.TryGetValue(id, out newValue) - something new I have learnt! :) – Haroon Mar 10 '11 at 11:27
0

You can't do that "easily", because there is no foreach equivalent in LINQ. That's on purpose. See http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx and LINQ equivalent of foreach for IEnumerable<T>.

I would suggest you just do a normal foreach over the query results.

Community
  • 1
  • 1
Jon
  • 428,835
  • 81
  • 738
  • 806
  • I am sure you can do it because I have done something very similar hence why I asked my question, I cannot figure out precisely how to do the lookup and where the setvalue should go: xelement.Descendants(TemplateElements.Div) .Where(x => Int32.Parse(x.Attribute(TemplateAttribute.BlockId).Value) == blockid) .FirstOrDefault() .SetValue(XmlView.HtmlLookup(htmlinput)); – Haroon Mar 10 '11 at 10:26
  • @Haroon: You *can* definitely do it. I 'm saying you *should not* do it. Is there a specific reason you want to? – Jon Mar 10 '11 at 10:42
  • It was because I wanted to keep everything in one code block as I did it with another code, ultimately it is my limited understanding of linq hence why i did not know any better, I shall have a look at the linq provided by yourself. – Haroon Mar 10 '11 at 11:22