【发布时间】:2014-12-31 13:00:09
【问题描述】:
我已经为此苦苦挣扎了一段时间。
我想将 html 转换为 xml。结构如下所示。
我正在使用“HtmlAgilityPack”将 html 转换为有效的 xml 结构。所以,在这之后,我的 HTML 看起来像这样:
<div class="menuItem1" video="" preview="">
Menu 1
<div class="subMenu1">
<div class="menuItem2" video="" preview="">
Menu 2
<div class="subMenu2">
<div class="menuItem3" video="" preview="">
Menu 3
<div class="subMenu3">
<div class="" video="" preview="">Menu 4</div>
</div>
<div class="treeExpand"></div>
</div>
<div class="menuItem3" video="" preview="">Menu 3</div>
<div class="menuItem3" video="" preview="">Menu 3</div>
</div>
<div class="treeExpand"></div>
</div>
</div>
<div class="treeExpand"></div>
</div>
<div class="menuItem1" video="" preview="">
Menu 1
<div class="subMenu1">
<div class="menuItem2" video="" preview="">
Menu 2
<div class="subMenu2">
<div class="menuItem3" video="" preview="">
Menu 3
<div class="subMenu3">
<div class="" video="" preview="">Menu 4</div>
</div>
<div class="treeExpand"></div>
</div>
<div class="menuItem3" video="" preview="">Menu 3</div>
<div class="menuItem3" video="" preview="">Menu 3</div>
</div>
<div class="treeExpand"></div>
</div>
</div>
<div class="treeExpand"></div>
</div>
这正是我想要的。现在我可以使用这个 C# 代码把它变成一个 XElement:
XDocument doc = XDocument.Parse(THE_HTML_STRING_AS_SHOWN_ABOVE);
XDocument docw = new XDocument(new XElement("Navigation", doc.Root));
XElement root = docw.Root;
我创建了一个方法,我可以将根传递给:
GenerateXmlFromHtml(root);
该方法的代码:
private string GenerateXmlFromHtml(XElement elem)
{
StringBuilder sbNavigationXml = new StringBuilder();
try
{
//HTML will always have a video and preview, according to the generation of the html structure.
string text = string.Empty;
string videopath = string.Empty;
string previewpath = string.Empty;
XText textNode;
foreach (XElement element in elem.Elements())
{
element.Name = "MenuItem"; //Change element name.
string htmlClass;
try { htmlClass = element.Attribute("class").Value; }
catch { htmlClass = ""; }
if (!string.IsNullOrEmpty(htmlClass))
{
if (htmlClass.Contains("subMenu"))
{
element.AddBeforeSelf(element.Elements());
element.Remove();
GenerateXmlFromHtml(element);
}
else if (htmlClass.Contains("menuItem"))
{
textNode = element.Nodes().OfType<XText>().FirstOrDefault();
text = textNode.Value;
videopath = element.Attribute("video").Value;
previewpath = element.Attribute("preview").Value;
if (element.HasElements)
{
sbNavigationXml.AppendLine("<MenuItem Text=\"" + text + "\" VideoPath=\"" + videopath + "\" PreviewPath=\"" + previewpath + "\">");
sbNavigationXml.AppendLine(GenerateXmlFromHtml(element));
sbNavigationXml.AppendLine("</MenuItem>");
}
else
{
sbNavigationXml.AppendLine("<MenuItem Text=\"" + text + "\" VideoPath=\"" + videopath + "\" PreviewPath=\"" + previewpath + "\" />");
}
}
else if (htmlClass.Contains("treeExpand"))
{
element.AddBeforeSelf(element.Elements());
element.Remove();
GenerateXmlFromHtml(element);
}
}
else
{
element.AddBeforeSelf(element.Elements());
element.Remove();
GenerateXmlFromHtml(element);
}
}
}
catch (Exception)
{
throw;
}
return sbNavigationXml.ToString();
}
最后,我希望它产生这个 XML 输出:
<Navigation>
<MenuItem Text="Menu 1" VideoPath="" PreviewPath="">
<MenuItem Text="Menu 2">
<MenuItem Text="Menu 3">
<MenuItem Text="Menu 4" VideoPath="" PreviewPath="" />
</MenuItem>
<MenuItem Text="Menu 3" />
<MenuItem Text="Menu 3" />
</MenuItem>
</MenuItem>
<MenuItem Text="Menu 1" VideoPath="" PreviewPath="">
<MenuItem Text="Menu 2">
<MenuItem Text="Menu 3">
<MenuItem Text="Menu 4" VideoPath="" PreviewPath="" />
</MenuItem>
<MenuItem Text="Menu 3" />
<MenuItem Text="Menu 3" />
</MenuItem>
</MenuItem>
</Navigation>
换句话说,子菜单应该消失,以及树展开 div,然后我想生成 XML,但目前,我仍然失败得很惨。请询问是否有不清楚的地方。任何帮助表示赞赏!
================================================ ==================================================== ==
编辑: 固定的递归方式,想看的人看:
private string GenerateXmlFromHtml(XElement elem)
{
//HTML will always have a video and preview, according to the generation of the html structure.
StringBuilder sbNavigationXml = new StringBuilder();
string text = string.Empty;
string videopath = string.Empty;
string previewpath = string.Empty;
XText textNode;
try
{
foreach (XElement element in elem.Elements())
{
//element.Name = "MenuItem"; //Change element name.
string htmlClass;
try { htmlClass = element.Attribute("class").Value; }
catch { htmlClass = ""; }
if (!string.IsNullOrEmpty(htmlClass))
{
if (htmlClass.Contains("subMenu"))
{
if (element.HasElements)
{
sbNavigationXml.AppendLine(GenerateXmlFromHtml(element));
}
}
else if (htmlClass.Contains("menuItem"))
{
textNode = element.Nodes().OfType<XText>().FirstOrDefault(); //Get node Text attribute value.
text = textNode.Value;
videopath = element.Attribute("video").Value; //Get node VideoPath attribute value.
previewpath = element.Attribute("preview").Value; //Get node PreviewPath attribute value.
if (element.HasElements)
{
sbNavigationXml.AppendLine("<MenuItem Text=\"" + text + "\" VideoPath=\"" + videopath + "\" PreviewPath=\"" + previewpath + "\">");
sbNavigationXml.AppendLine(GenerateXmlFromHtml(element));
sbNavigationXml.AppendLine("</MenuItem>");
}
else
{
sbNavigationXml.AppendLine("<MenuItem Text=\"" + text + "\" VideoPath=\"" + videopath + "\" PreviewPath=\"" + previewpath + "\" />");
}
}
else if (htmlClass.Contains("treeExpand"))
{
//DO NOTHING
}
}
else
{
if (element.HasElements)
{
sbNavigationXml.AppendLine(GenerateXmlFromHtml(element));
}
}
}
}
catch (Exception)
{
throw;
}
return sbNavigationXml.ToString();
}
【问题讨论】:
-
旁注:通常人们会以其他方式误解 - 使用 Regex 解析 HTML,但仍然使用适当的 API 构造 XML。为什么需要使用字符串连接来构建 XML?
-
@AlexeiLevenkov - 不,我可以做任何我想做的事情......这只是我所走的路,但任何其他产生 XML 输出的东西都可以,即使我必须这样做完全不同的东西。
-
查看How can I build XML in C# 以获得指导。
-
@AlexeiLevenkov - 这很好,但我认为我的递归方法有问题。因为我没有看到所有的节点。似乎只到了第二个菜单项级别。
-
建议:您正在更改 HTML 树,同时遍历它。它使代码几乎无法理解。尽量避免这样做,它可能会自行修复。
标签: c# html xml recursion html-agility-pack