2012-07-26 68 views
0

我想弄清楚如何將具有相同名稱但不同值的XML節點分組。如何分組同名的XML節點?

我使用的是回報,看起來像這樣的XmlElement的Web服務:

<Items> 
    <Item> 
     <Name name="Name">Item 1</Name> 
     <Description name="Description"> 
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
     </Description> 
     <AssociatedItems name="Associated Items">Item 2</AssociatedItems> 
     <AssociatedItems name="Associated Items">Item 3</AssociatedItems> 
     <AssociatedItems name="Associated Items">Item 4</AssociatedItems> 
     <AssociatedItems name="Associated Items">Item 5</AssociatedItems> 
    </Item> 
</Items> 

我將每個節點插入HTML標籤

protected void lnkItem_Click(object sender, EventArgs e) 
{ 
    LinkButton link = (LinkButton)sender; 
    GridViewRow row = (GridViewRow)link.Parent.Parent; 

    string id = gv.DataKeys[row.RowIndex]["id"].ToString(); 

    PublicApiAsmxServiceSoapClient service = new PublicApiAsmxServiceSoapClient("PublicApiAsmxServiceSoap", WEB_SERVICE_URL); 
    XmlElement xml = service.ItemGetAsXml(id); 
    XElement nodes = XElement.Parse(xml.InnerXml); 

    foreach (var node in nodes.Elements()) 
    { 
     InsertHTML(node); 
    } 
} 

private void InsertHTML(XElement node) 
{ 
    if (node.Value == string.Empty) 
     return; 

    pnl.ContentTemplateContainer.Controls.Add(new LiteralControl(String.Format("<h3>{0}</h3>", node.Attribute("name").Value))); 
    pnl.ContentTemplateContainer.Controls.Add(new LiteralControl(String.Format("<p>{0}</p>", node.Value))); 
} 

我的代碼,現在,在HTML輸出將是:

<h3>Name</h3> 
<p>Item 1</p> 
<h3>Description</h3> 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> 
<h3>Associated Items</h3> 
<p>Item 2</p> 
<h3>Associated Items</h3> 
<p>Item 3</p> 
<h3>Associated Items</h3> 
<p>Item 4</p> 
<h3>Associated Items</h3> 
<p>Item 5</p> 

有沒有辦法將同一個節點組成一個無序列表?可能是這樣的:

<h3>Name</h3> 
<p>Item 1</p> 
<h3>Description</h3> 
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> 
<h3>Associated Items</h3> 
<ul> 
    <li>Item 2</li> 
    <li>Item 3</li> 
    <li>Item 4</li> 
    <li>Item 5</li> 
</ul> 

謝謝! (請當心)

ps 重複的子節點不僅限於AssociatedTerms。有可能有更多的同名重複的子節點。

+0

這是非常好的[鏈接](HTTP ://www.silverlight.net/learn/data-networking/linq/linq-to-xml-%28silverlight-quickstart%29)。使用LINQ to XML,你可以完成你想要的。尋找在這個鏈接中按類別分組一個RSS XML樹 2012-07-26 04:47:31

回答

1

這將是最容易的,因爲被生成的內容取決於有多少有重複的。

據我所知,你正在按元素名稱和name屬性的值進行分組。然後根據組中是否有多個元素生成h3後跟一個元素。如果存在單個元素,或者存在多個元素,則返回ul

IEnumerable<XElement> GroupedElements(XElement root) 
{ 
    var groupedItems = 
     from element in root.Elements() 
     group element 
     by new 
     { 
      Element = element.Name, 
      Name = (string)element.Attribute("name"), 
     }; 
    foreach (var g in groupedItems) 
    { 
     yield return new XElement("h3", g.Key.Name); 
     var isMultiple = g.Skip(1).Any(); 
     if (isMultiple) 
      yield return new XElement("ul", 
       from item in g 
       select new XElement("li", item.Value.Trim()) 
      ); 
     else 
      yield return new XElement("p", g.Single().Value.Trim()); 
    } 
} 
var xmlStr = @"<Items> 
    <Item> 
     <Name name=""Name"">Item 1</Name> 
     <Description name=""Description""> 
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
     </Description> 
     <AssociatedItems name=""Associated Items"">Item 2</AssociatedItems> 
     <AssociatedItems name=""Associated Items"">Item 3</AssociatedItems> 
     <AssociatedItems name=""Associated Items"">Item 4</AssociatedItems> 
     <AssociatedItems name=""Associated Items"">Item 5</AssociatedItems> 
    </Item> 
</Items>"; 
var doc = XDocument.Parse(xmlStr); 
var transformed = new XElement("div", 
    from item in doc.XPathSelectElements("/Items/Item") 
    select GroupedElements(item) 
); 

產生如下:

<div> 
    <h3>Name</h3> 
    <p>Item 1</p> 
    <h3>Description</h3> 
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p> 
    <h3>Associated Items</h3> 
    <ul> 
    <li>Item 2</li> 
    <li>Item 3</li> 
    <li>Item 4</li> 
    <li>Item 5</li> 
    </ul> 
</div> 
+0

我其實寫了一些像這樣的東西。謝謝! :) – dork 2012-07-26 07:49:18

0

我不知道這是否是最好的解決辦法,但你可以使用產生器,基於對分組的元素嘗試這樣的事情

 List<string> items = new List<string>(); 
      XmlReader rdr = XmlReader.Create(new System.IO.StringReader(xml)); 
      while (rdr.Read()) 
      { 
      if (rdr.NodeType == XmlNodeType.Element) 
      { 
       InsertHTML(rdr.LocalName.ToString(), rdr.Value.ToString()); 
      } 
      } 
     private void InsertHTML(string name, string value) 
     { 
      if (value == string.Empty) 
       return; 
      if(name=="AssociatedItems") 
      { 

       items.add(value); 
      } 
      else 
      { 
      pnl.ContentTemplateContainer.Controls.Add(new LiteralControl(String.Format("<h3>{0}</h3>", name))); 
      pnl.ContentTemplateContainer.Controls.Add(new LiteralControl(String.Format("<p>{0}</p>", value))); 
      } 
     } 
      pnl.ContentTemplateContainer.Controls.Add(new LiteralControl(String.Format("<h3>{0}</h3>", "Associated Items"))); 
      pnl.ContentTemplateContainer.Controls.Add(new LiteralControl(String.Format("<ul>"))); 
     foreach(var item in items) 
     { 

      pnl.ContentTemplateContainer.Controls.Add(new LiteralControl(String.Format("<li>{0}</li>", item))); 

     } 
     pnl.ContentTemplateContainer.Controls.Add(new LiteralControl(String.Format("</ul>"))); 
+0

事情是,它有更多的節點。所以可以有其他節點名稱相同。 – dork 2012-07-26 03:33:08

+0

ohh你的意思是任何你想在列表中查看的同名元素 – 2012-07-26 03:34:12

+0

@omgdork他們不是真正的子元素,你可以用不同的格式化你的xml以使它們成爲子元素 – 2012-07-26 03:38:01

0

如果你想使用XSLT,你可以這樣做:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" indent="yes"/> 

    <xsl:key name="grouping" match="Item/*" use="@name"/> 

    <xsl:template match="Item"> 
    <xsl:apply-templates 
     select="*[generate-id(.)=generate-id(key('grouping', @name)[1])]"/> 
    </xsl:template> 

    <xsl:template match="Item/*"> 
    <h3><xsl:value-of select="@name"/></h3> 
    <xsl:choose> 
     <xsl:when test="count(key('grouping', @name))=1"> 
     <p><xsl:value-of select="normalize-space(.)"/></p> 
     </xsl:when> 
     <xsl:otherwise> 
     <li> 
      <xsl:for-each select="key('grouping', @name)"> 
      <ul><xsl:value-of select="normalize-space(.)"/></ul> 
      </xsl:for-each> 
     </li> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet>