使用XML创建HTML表单来定义布局c#

本文关键字:定义 布局 表单 XML 创建 HTML 使用 | 更新日期: 2023-09-27 18:12:21

我在下面的模式中有一些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#,因为我将把它包装成一个控件,我可以把它放到任何页面中。

我的问题是,我怎样才能实现这样的事情?我设想它需要某种类型的嵌套开关语句来检查节点名称和类型等,以及HTML的字符串构建。但是,我希望情况不是这样,你们这些科学家可以帮我指出正确的方向。

Thanks in advance:)

戴夫

使用XML创建HTML表单来定义布局c#

实现这一点的一种方法是设计一些对象来表示您想要生成的各种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.

Ok !我们就快到了。下一步是将该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示例来展示如何工作。

很抱歉证实你的担心,但没有"通用"或"简单"的方法来做到这一点。

正如您所提到的,XSLT是标准实践,如果做不到这一点,您就需要构建某种自定义解析器/字符串构建器来做同样的事情。

我想到的一种方法就是使用MVC框架来减少你的工作量。

MVC框架具有类似于"autobinder"的功能,基本上可以接受任何类并生成适当的HTML(使用任何视图引擎)。

因此,如果您选择了这条路线,那么您的任务将仅限于简单地解析XML并创建格式良好的注释装饰类。然后MVC框架将能够在HTML中为您生成所有CRUD视图。

希望有帮助,干杯。

我不知道您对使用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文件是您在原始问题中所述的内容和样式。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>

祝你好运!