javascript - Getting nested XML data with D3 - Stack Overflow

My excel file, called thefilehere.xml contains the following information:<Main><Name>Rotund

My excel file, called thefilehere.xml contains the following information:

<Main>
  <Name>Rotunda</Name>
  <Age>43</Age>
</Main>
<Main>
  <Name>John</Name>
  <Age>22</Age>
</Main>

As someone who has litle experience with D3 and XML files, I am trying to understand how to call the nested data from my XML file. My basic HTML is as follows:

HTML

<div id="chart"></div> 

My Javascript, which does not work, hopefully makes it clear what I am trying to acplish. I want to select the main container (in this case Main), and from there select its children (in this case Name and Age). Age is to be shown via graph. Name is to be the label on the graph.

JavaScript

  d3.xml("thefilehere.xml", function(err, xml) {
    d3.select("#chart")
    .selectAll("div")
    .data(xml.documentElement.getElementsByTagName("Main"))
    .enter().append("div")
    .style("width", function(d) { return d("Age").textContent * 1 + "px"; })
    .text(d("Name").textContent);
  });

My excel file, called thefilehere.xml contains the following information:

<Main>
  <Name>Rotunda</Name>
  <Age>43</Age>
</Main>
<Main>
  <Name>John</Name>
  <Age>22</Age>
</Main>

As someone who has litle experience with D3 and XML files, I am trying to understand how to call the nested data from my XML file. My basic HTML is as follows:

HTML

<div id="chart"></div> 

My Javascript, which does not work, hopefully makes it clear what I am trying to acplish. I want to select the main container (in this case Main), and from there select its children (in this case Name and Age). Age is to be shown via graph. Name is to be the label on the graph.

JavaScript

  d3.xml("thefilehere.xml", function(err, xml) {
    d3.select("#chart")
    .selectAll("div")
    .data(xml.documentElement.getElementsByTagName("Main"))
    .enter().append("div")
    .style("width", function(d) { return d("Age").textContent * 1 + "px"; })
    .text(d("Name").textContent);
  });
Share Improve this question asked Apr 20, 2017 at 16:11 Jason ChenJason Chen 2,5876 gold badges27 silver badges47 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5

This answer adds to and builds upon the work already done by @GerardoFurtado in his answer which is perfectly fine and well-suited for many situations. However, as it is often times desirable to stay within D3 to not break its basic operating concepts, here is my D3-only—mostly, at least— solution.

Since D3 is not restricted to handling SVG DOM trees, but is capable of handling—amongst others—XML DOM just as well, you can easily use its selections on the loaded XML file. The relevant code might look like this:

d3.xml(url, (error, xml) => {
  let xmlDoc = d3.select(xml.documentElement);   // wrap the XML document in a D3 selection

  d3.select("body")
    .selectAll("div")
    .data(xmlDoc.selectAll("Main").nodes())      // bind the XML's nodes as data
    .enter().append("div")
      .attr("class", "myDiv")
      .style("width", d => d3.select(d).select("Age").text() * 5 + "px")
      .text(d => d3.select(d).select("Name").text());
});

When doing d3.select(d) within .style() and .text() it is important to notice, that this will actually select from the XML's DOM rather than from the HTML's DOM. Since we bound the selected elements from xmlDoc.selectAll("Main") as data, d in this case will refer to a <Main> element of the XML. Having this selection at hand, you can leverage D3's capabilities by doing sub-selections as well as accessing its contents by calling .text() and much more, if needed.

Have a look at the following snippet for a working demo:

// Set up data to simulate loading from file.
// This can be ignored for the reasoning of this answer; main logic below.
const url = URL.createObjectURL(new Blob([
  `<data>
     <Main>
       <Name>Rotunda</Name>
       <Age>43</Age>
     </Main>
     <Main>
       <Name>John</Name>
       <Age>22</Age>
     </Main>
   </data>`
]));
// End of setup.

// Main logic
d3.xml(url, (error, xml) => {
  let xmlDoc = d3.select(xml.documentElement);

  d3.select("body")
    .selectAll("div")
    .data(xmlDoc.selectAll("Main").nodes())
    .enter().append("div")
      .attr("class", "myDiv")
      .style("width", d => d3.select(d).select("Age").text() * 5 + "px")
      .text(d => d3.select(d).select("Name").text());
});
.myDiv{
  background-color: lightblue;
  margin: 4px;
}
<script src="https://d3js/d3.v4.js"></script>

Firstly, we'll change your XML structure, wrapping all your data inside a tag. Traditionally, this tag is named data:

<data>
    <main>
        <name>Rotunda</name>
        <age>43</age>
    </main>
    <main>
        <name>John</name>
        <age>22</age>
    </main>
</data>

After that, inside your d3.xml callback, you could simply use...

xml = xml.getElementsByTagName("main");

However, since inside <main> you have two tags with data, it will be awkward getting that data with textContent. This solution by Mike Bostock is way more interesting:

xml = [].map.call(xml.querySelectorAll("main"), function(d) {
    return {
        name: d.querySelector("name").textContent,
        age: +d.querySelector("age").textContent
    };
});

Now, you just need to use name and age in your code, which will be like this:

d3.xml("thefilehere.xml", function(err, xml) {

    xml = [].map.call(xml.querySelectorAll("main"), function(d) {
        return {
            name: d.querySelector("name").textContent,
            age: +d.querySelector("age").textContent
        };
    });

    d3.select("body")
        .selectAll("div")
        .data(xml)
        .enter()
        .append("div")
        .attr("class", "myDiv")
        .style("width", function(d) {
            return d.age * 5 + "px";
        })
        .text(function(d) {
            return d.name
        });
});

Since I can't use d3.xml in the Stack snippet, here is a plunker with the working code: https://plnkr.co/edit/e9aCsHZnPiV4fBaPvAZv?p=preview

To be able to get the data with d3.xml, you have to be serving thefilehere.xml from a local server.

This will not work if thefilehere.xml is simply a file in the same directory as your HTML & JS.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745082255a4610200.html

相关推荐

  • javascript - Getting nested XML data with D3 - Stack Overflow

    My excel file, called thefilehere.xml contains the following information:<Main><Name>Rotund

    11小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信