代码之家  ›  专栏  ›  技术社区  ›  Maverick Meerkat

JS:基于节点解析XML并更新控件

  •  2
  • Maverick Meerkat  · 技术社区  · 8 年前

    我在采访中被问到这个问题。任务是在客户端解析xml,并用其内容填充html页面。还有人问 不 使用jQuery。

    理想情况下,我甚至不知道XML上有什么,只需为其中的每个节点/元素添加一个标签。但假设我确实知道xml的样子:

    <?xml version="1.0" encoding="UTF-8"?> 
    <cv>
        <FirstName>David</FirstName>
        <LastName>Refaeli</LastName>
        <Jobs>Worst JS Programmer</Jobs>
    </cv>
    

    我的服务器端html是:

    <body>
        <form id="form1" runat="server">
            <div>
                <asp:TextBox ID="TextBox1" runat="server" Height="185px" Width="279px"></asp:TextBox><br />
                <asp:Button ID="Button1" runat="server" Text="Button" OnClientClick="return ParseXml();" /><br />
                <br />
                <asp:Label ID="FirstName" runat="server" Text=""></asp:Label><br />
                <asp:Label ID="LastName" runat="server" Text=""></asp:Label><br />
                <asp:Label ID="Jobs" runat="server" Text=""></asp:Label><br />
            </div>
        </form>
    </body>
    </html>
    

    假设文本框包含xml。我已经为xml中的文本设置了占位符标签。

    我试着运行这个JS(以及许多其他变体),但失败了,在VS中调试它似乎找不到原因(它会突然将我弹出到一个jQuery文件中…)所以我猜我走错了方向。

    <script>
        function ParseXml() {
            var text = document.getElementById('<% = TextBox1.ClientID %>');
            parser = new DOMParser();
            xmlDoc = parser.parseFromString(text.textContent, "text/xml");
            var a1 = xmlDoc.getElementsByTagName("cv")[0].childNodes[0].nodeValue;
            var a2 = xmlDoc.getElementsByTagName("cv")[0].childNodes[1].nodeValue;
            var a3 = xmlDoc.getElementsByTagName("cv")[0].childNodes[2].nodeValue;
            document.getElementById('<% = FirstName.ClientID %>').textContent = a1;
            document.getElementById('<% = LastName.ClientID %>').textContent = a2;
            document.getElementById('<% = Jobs.ClientID %>').textContent = a3;
            return true;
        }
    </script>
    

    任何帮助都将不胜感激。

    3 回复  |  直到 8 年前
        1
  •  1
  •   derloopkat    8 年前

    当函数返回true时,会将表单发布到服务器,因此您会得到新表单,并丢失所有Javascript更改。第一个变化是返回false以防止发帖返回。然后我改变了从xml中检索文本的方式。

    function ParseXml() {
        var xml = document.getElementById('<% = TextBox1.ClientID %>').value;
        var parser = new DOMParser();
        xmlDoc = parser.parseFromString(xml, "text/xml");
        var firstName = xmlDoc.getElementsByTagName("FirstName")[0].childNodes[0].nodeValue;
        var lastName = xmlDoc.getElementsByTagName("LastName")[0].childNodes[0].nodeValue;
        var jobs = xmlDoc.getElementsByTagName("Jobs")[0].childNodes[0].nodeValue;
        document.getElementById('<% = FirstName.ClientID %>').innerText = firstName;
        document.getElementById('<% = LastName.ClientID %>').textContent = lastName;
        document.getElementById('<% = Jobs.ClientID %>').textContent = jobs;
        return false;
    };
    

    或者,如果你不知道里面的字段 个人简历 tag,你可以这样做:

    var tags = xmlDoc.getElementsByTagName("cv")[0].childNodes;
    for (key in tags)
    {
        if (tags[key].nodeName.length) {
            document.body.innerHTML += '<b>'
                + tags[key].nodeName + ':</b> '
                + tags[key].textContent + '<br />';
        }
    }
    

    我也有残疾 ValidateRequest 在您的Aspx中:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication14.WebForm2" ValidateRequest="false" %>
    

    通过这些更改,代码应该能够像这样解析xml:

    <?xml version="1.0" encoding="UTF-8"?> 
    <cv>
        <FirstName>David</FirstName>
        <LastName>Refaeli</LastName>
        <Jobs>Worst JS Programmer</Jobs>
    </cv>
    

    在你的尝试中,原因是 xmlDoc.getElementsByTagName("cv")[0].childNodes[0].nodeValue 不回名字是因为 childNodes 包含额外的 text 标记之间的空格和新行字符的节点。所以阵列看起来像:

    0:text,1:firstname,2:text,3:lastname,4:text,5:jobs,6:text

    名字是项目1,而不是0。但由于xml上只有一个CV,我可以通过以下方式访问:

    xmlDoc.getElementsByTagName("FirstName")[0].childNodes[0].nodeValue;
    
        2
  •  1
  •   chriopp    8 年前

    不确定服务器端HTML是否是问题的一部分,但我想不是。 为了证明概念,我将继续使用您的示例XML,并从数据中构建文本输入。 表单内容是在AJAX调用后加载页面时动态创建的,因此您必须使用服务器才能看到它的工作情况。所有三个文件应并排放置。

    HTML页面(index.HTML)

    <!doctype html>
    <html>
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
        </head>
        <body style="margin:50px">
            <form>
                <h1>Dynamic Form</h1>
                <div id="form-content"></div>
                <button>some action</button>
            </form>
            <script src="index.js"></script>
        </body>
    </html>
    

    数据(Data.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <cv>
        <FirstName>David</FirstName>
        <LastName>Refaeli</LastName>
        <Jobs>Aspiring JS Programmer</Jobs>
    </cv>
    

    JavaScript代码(index.js)

    // create a label from a string and append to parent DOM element
    function addLabel(parent, name) {
        var wrapper = document.createElement('div');
        var label = document.createElement('label');
        label.innerHTML = name;
        wrapper.appendChild(label);
        parent.appendChild(wrapper);
    }
    // create a text input from a with id and value 
    // and append to parent DOM element
    function addTextbox(parent, id, value) {
        var box = document.createElement('input');
        box.type = 'text';
        box.id = id;
        box.value = value;
        parent.appendChild(box);
    }
    // create a input with label for text with id and value
    function createTextbox(id, value) {
        var form = document.getElementById('form-content');
        addLabel(form, id);
        addTextbox(form, id, value);
    }
    // upload the data that defines dynamic text inputs for a 
    // form and create the form
    function update () {
        var xhr = new XMLHttpRequest();
        xhr.onload = function () {
            var values = xhr.responseXML.documentElement.children;
            var length = values.length;
            for (var i = 0; i < length; i++) {
                var node = values[i];
                var name = node.nodeName;
                var value = node.innerHTML;
                createTextbox(name, value);
            };
        };
        xhr.onerror = function (error) {
            console.error(error);
        };
        xhr.responseType = 'document';
        xhr.open('GET', 'data.xml');
        xhr.send();
    }
    
    // simplistic onload :-)
    update();
    

    正如您所见,输入的解析和创建是分开的。现在,如果我们将XML与实际的输入类型(例如文本、收音机、复选框)联系起来,我们可以扩展代码,根据数据创建不同的输入字段,最终创建一个真正的复杂表单,完全由XML定义。

        3
  •  0
  •   Ivan Ferić    8 年前

    面试官想看看你是否知道如何进行XSLT转换(或者只是想看看你是否知道这个概念)。

    我在原始XML上添加了一个CVs列表,并添加了XSLT转换模板,该模板将创建 <h1> 标题和一个将输出CV列表的表——每个CV位于单独的行中,每个属性位于单独的列中。然而,你可以随心所欲地设计它。

    单击按钮时运行的代码将从一个textarea加载XML对象,从另一个textarea加载xslt对象。然后它会使用 XSLTProcessor 对象导入XSLT样式表,并使用它将XML转换为HTML片段 transformToFragment 函数并将该片段放入 <div> 要素

    以下是您可以查看的全部片段:

    function Transform()
    {
      var parser = new DOMParser();
      var xml = parser.parseFromString(document.getElementById('xml').value, 'text/xml');
      var xslt = parser.parseFromString(document.getElementById('xslt').value, 'text/xml');
      
      var xsltProcessor = new XSLTProcessor();
      xsltProcessor.importStylesheet(xslt);
      resultDocument = xsltProcessor.transformToFragment(xml, document);
      document.getElementById('output').appendChild(resultDocument);
    }
    <html>
    <body>
    <p><label for="xml">XML:</label></p>
    <textarea id="xml" rows=14 cols=100>
    <?xml version="1.0" encoding="UTF-8"?>
    <cvs>
      <cv>
        <FirstName>David</FirstName>
        <LastName>Refaeli</LastName>
        <Jobs>Worst JS Programmer</Jobs>
      </cv>
      <cv>
        <FirstName>Ivan</FirstName>
        <LastName>Ferić</LastName>
        <Jobs>Bounty hunter</Jobs>
      </cv>
    </cvs>
    </textarea>
    
    <p><label for="xslt">XSLT:</label></p>
    <textarea id="xslt" rows=21 cols=100>
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
        <h2>CVs</h2>
        <table border="1">
          <tr bgcolor="#9acd32">
            <th style="text-align:left">First Name</th>
            <th style="text-align:left">Last Name</th>
            <th style="text-align:left">Jobs</th>
          </tr>
          <xsl:for-each select="cvs/cv">
          <tr>
            <td><xsl:value-of select="FirstName" /></td>
            <td><xsl:value-of select="LastName" /></td>
            <td><xsl:value-of select="Jobs" /></td>
          </tr>
          </xsl:for-each>
        </table>
      </xsl:template>
    </xsl:stylesheet>
    </textarea>
    
    <p><button onclick="Transform()">Transform</button></p>
    
    <p>Output:</p>
    <div id="output"></div>
    </body>
    </html>
    推荐文章