【问题标题】:Creating HTML form using XML to define layout C#使用 XML 创建 HTML 表单以定义布局 C#
【发布时间】:2011-12-15 15:08:46
【问题描述】:

我在以下架构中有一些 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。但是,我希望情况并非如此,你们这些研究人员可以帮助我指出正确的方向。

提前致谢:)

戴夫

【问题讨论】:

标签: c# xml .net-3.5


【解决方案1】:

我不知道您对使用 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>

祝你好运!

【讨论】:

    【解决方案2】:

    实现这一点的一种方法是设计一些对象来表示您想要生成的各种 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 示例来展示它是如何工作的。

    【讨论】:

      【解决方案3】:

      很抱歉确认您的担心,但没有“通用”或“简单”的方法可以做到这一点。

      正如您所提到的,XSLT 是标准做法,如果失败,您需要构建某种自定义解析器/字符串构建器来做同样的事情。

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

      MVC 框架带有类似“autobinder”的功能,它基本上采用任何类并生成适当的 HTML(使用哪个视图引擎)。

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

      希望有帮助,干杯。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-22
        • 1970-01-01
        • 2011-07-27
        相关资源
        最近更新 更多