JS:根据节点解析XML和更新控件

时间:2018-05-29 08:39:50

标签: javascript asp.net xml

我在接受采访时被问到这个问题。任务是在客户端解析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文件......)所以我&# 39;我猜我错了。

<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 个答案:

答案 0 :(得分:1)

当函数返回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;
};

或者,如果您不知道 cv 标记内的字段,则可以执行以下操作:

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 />';
    }
}

我也在你的Aspx中禁用了ValidateRequest

<%@ 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上只有一个简历,我可以使用这个来访问:

xmlDoc.getElementsByTagName("FirstName")[0].childNodes[0].nodeValue;

答案 1 :(得分:1)

不确定服务器端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定义的真实复杂形式。 / p>

答案 2 :(得分:0)

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

我在原始XML上添加了一个CV列表,并添加了将创建<h1>标题的XSLT转换模板和一个将输出CV列表的表 - 每个CV在一个单独的行中,每个属性在一个单独的专栏。但是,您可以按照自己想要的方式设置样式。

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