我在以下架构中有一些XML:
<Form ID="1" Formtitle="Title">
<Fields>
<Fieldset Legend="LegendText" >
<Field FieldName="Field1" Label="Title" Type="Text" Required="1" />
<Field FieldName="Field2" Label="Radio" Type="Radio" Required="0">
<Option Value="1" Text="Just One"/>
<Option Value="2" Text="Maybe Two"/>
</Field>
</Fieldset>
</Fields>
</Form>
我需要在C#中解析这个以生成一个代表以下内容的HTML表单:
<h1>Formtitle</h1>
<form id="1" action="myurl.com">
<fieldset>
<legend>LegendText</legend>
<label>Title</label>
<input type="text" name="Field1" class="jqueryValidate"/>
<!-- jqueryvalidate class added as required is equal to 1 in XML -->
<label>Radio</label>
<input type="radio" name="Field2" Value="1"/> Just One
<input type="radio" name="Field2" Value="2"/> Maybe Two
</fieldset>
</form>
现在,我知道我可以使用XSLT实现同样的功能,但是我必须在这里使用C#,因为我将把它包装到一个控件中,我可以放入任何一个页面。
我的问题是,我怎么能这样做?我设想它需要某种类型的嵌套switch语句来检查节点名称和类型等,并构造HTML。但是,我希望情况并非如此,你们的boffins可以帮助我指出正确的方向。
提前致谢:)
戴夫
答案 0 :(得分:0)
很抱歉确认您的担忧,但没有“通用”或“简单”的方法来执行此操作。
正如您所提到的,XSLT是标准做法,如果失败,您需要构建某种自定义解析器/字符串构建器,它会执行相同的操作。
我们想到的一种方法是使用MVC框架来减轻您的工作量。
MVC框架带有'autobinder'之类的功能,基本上可以接受任何类并生成适当的HTML(使用哪种视图引擎)。
因此,如果您选择了该路由,您的任务将仅限于简单解析XML并创建格式良好的注释装饰类。然后,MVC框架将能够以HTML格式为您生成所有CRUD视图。
希望有所帮助,干杯。
答案 1 :(得分:0)
实现此目的的一种方法是设计一些表示您要生成的各种HTML实体的对象。请注意,这是一个非常非常简化的示例。你可以拥有一个基类,里面有各种各样的技巧和可重用性。但这超出了问题的范围,我们都会在这里整天待在这里:)
public interface IElement
{
string RenderStart();
string RenderEnd();
string Render();
IList<IElement> Children { get; }
void LoadFromXML(XmLReader reader);
} // eo interface IElement
public abstract class Element : IElement
{
List<IElement> children_ = new List<IElement>();
public List<IElement> Children { get { return children_; } }
public string Render()
{
StringBuilder builder = new StringBuilder(RenderStartTag());
foreach(IElement e in children_)
builder.Append(e.Render());
builder.Append(RenderEndTag());
return builder.ToString();
}
} // eo class Element
public class FieldSetElement : Element
{
public string RenderStart()
{
StringBuilder builder = new StringBuilder();
builder.Append("<fieldset legend=\"")
.Append("\">");
return builder.ToString();
}
public string RenderEnd()
{
return ("</fieldset>");
}
public string Legend {get; set; }
public void LoadFromXml(XmlReader reader)
{
Legend = reader.GetAttribute("legend");
} // eo LoadFromXml
} // eo class FieldSet
显然,每个HTML元素都有一个Element
派生类。我们还有一种方法可以从Xml节点初始化它们。但是现在,我们需要将我们的Xml标签与我们的DOM对象相关联。我们可以使用字典来做到这一点(在这个简单的例子中。我更喜欢一个完整的工厂,但是再次 - 这超出了这个答案的范围!)
public delegate IElement ElementCreator;
Dictionary<string, ElementCreator> creators_ = new Dictionary<string, ElementCreator>
我会继续为FieldSet
元素添加一个:
creators_["fieldset"] = () => { return new FieldSet(); };
// and so on for other creators and elements.
确定!我们快到了。下一步是将该XML文档转换为对象。我想在这一点上我们会有一些根对象。我打电话给Html
(令人惊讶的名字!)。你可以猜到,它也来自Element
。它将作为我们的根节点。
Html root = new Html();
现在,我们需要一个函数来读取Xml并将其转换为我们当前的父级。
XmlReader reader = new XmlReader("layout.xml");
Stack<IElement> currentRoot = new Stack<IElement>();
currentRoot.Push(root);
while(reader.Read())
{
// get the element tag
if(reader.NodeType == XmlNodeType.Element)
{
Debug.Assert(creators_.ContainsKey(reader.Name)); // must have it!
IElement newElement = creators_[reader.Name].Invoke(); // create it
newElement.LoadFromXml(reader); // tell element to read itself in
currentRoot.Peek().Children.Add(newElement); // add to parent
currentRoot.Push(newElement); // we are now new parent
}
else if(reader.NodeType == XmlNodeType.EndElement)
currentRoot.Pop(); // just pop it off!
}
哇!我们几乎完成了。此时,我们有一个对象集合!剩下的就是渲染它们。
string html = root.Render();
BAM。我们已经完成了。
很抱歉,如果代码中有任何错误,我会尝试重复一遍。我没有跑过这个,但我之前做过类似的事。我也不是说这是最好的方式,我相信还有其他方法。这是一种方式。出于简洁的原因,我遗漏了属性的渲染,但我很乐意添加另一个具体的Element
示例来说明这可能有用。
答案 2 :(得分:0)
我不知道您对使用XSLT有多厌恶,但您可以通过在C#中使用XSLT实现此目的。
using System.Xml.Xsl;
namespace XmlTransform
{
class Program
{
static void Main(string[] args)
{
// Load the style sheet.
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(@"C:\style.xsl");
// Execute the transform and output the results to a file.
xslt.Transform(@"C:\input.xml", @"C:\result.html");
Console.WriteLine("Result saved to C:\result.html");
Console.ReadLine();
}
}
}
input.xml文件是您在原始问题中声明的内容,而style.xsl看起来像这样
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/Form">
<html>
<body>
<h1><xsl:value-of select="@Formtitle"/></h1>
<form id="1" action="myurl.com">
<fieldset>
<legend><xsl:value-of select="Fields/Fieldset/@Legend"/></legend>
<label>Title</label>
<xsl:for-each select="Fields/Fieldset/Field">
<xsl:if test="@Type = 'Text'">
<xsl:if test="@Required='1'">
<input type="text" name="{@FieldName}" class="jqueryValidate"/>
</xsl:if>
<xsl:if test="@Required='0'">
<input type="text" name="{@FieldName}"/>
</xsl:if>
</xsl:if>
<xsl:if test="@Type = 'Radio'">
<xsl:if test="@Required='1'">
<label><xsl:value-of select="@Label"/></label>
<input type="radio" name="{FieldName}"/>" class="jqueryValidate"/>
</xsl:if>
<xsl:if test="@Required='0'">
<label><xsl:value-of select="@Label"/></label>
<xsl:for-each select="Option">
<input type="radio" name="Field2" Value="1"/> Just One
</xsl:for-each>
</xsl:if>
</xsl:if>
</xsl:for-each>
</fieldset>
</form>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
祝你好运!