2

I am trying to use <xsl:copy-of> to submit copies of two XML nodes along with a form. The problem is that I'm only getting the node's text content instead of all of the full node content. According to w3schools:

The <xsl:copy-of> element creates a copy of the current node. Note: Namespace nodes, child nodes, and attributes of the current node are automatically copied as well!

But, this doesn't seem to be happening for me -- either I don't understand the note, or I'm using the <xsl:copy-of> element incorrectly. I've included snippets of my xml, xsl, and jQuery below (I apply the xsl to the xml, which creates an html form, which uses jQuery to submit). I've also included the output I'm currently getting along with the desired output. Any suggestions are much appreciated!

The XML looks like this:

<trigger offsetBeg="89" offsetEnd="96">induced</trigger>
<ggps>
    <ggp role="Theme" offsetBeg="68" offsetEnd="73" id="10013" 
     consensusName="HDAC6">HDAC6</ggp>
    <ggp role="Cause" offsetBeg="100" offsetEnd="103" id="7001" 
     consensusName="TSA">TSA</ggp>
</ggps>

The XSL looks like this:

<xsl:variable name="trigger"><xsl:copy-of select="trigger" /></xsl:variable>
<xsl:variable name="ggps"><xsl:copy-of select="ggps" /></xsl:variable>
<form name="label_form" action="">
    <input class="trigger" type="hidden" name="trigger" value="{$trigger}" />
    <input class="ggps" type="hidden" name="ggps" value="{$ggps}" />
    <div><button class="button">Submit</button></div>
</form>

When I add this to the XSL:

<xsl:copy-of select="current()/trigger"></xsl:copy-of>
<xsl:copy-of select="current()/ggps"></xsl:copy-of>

I get this HTML:

<trigger offsetBeg="89" offsetEnd="96">induced</trigger>
<ggps>
    <ggp role="Theme" offsetBeg="68" offsetEnd="73" id="10013" 
     consensusName="HDAC6">HDAC6</ggp>
    <ggp role="Cause" offsetBeg="100" offsetEnd="103" id="7001" 
     consensusName="TSA">TSA</ggp>
</ggps>

I'm using jQuery to do the form submission:

$(".button").click(function() {
    var trigger = $(this).parent().siblings("input.trigger").val();
    var ggps = $(this).parent().siblings("input.ggps").val();
    var dataString = 'trigger=' + trigger + '&ggps=' + ggps;    

    $.ajax({
        type : "POST",
        url : "/submit_label",
        data : dataString,
        success : function(){
            console.log("dataString:\n" + dataString);
        }
    });
    return false;
});

What I'm getting out of console.log is this:

dataString:
trigger='induced   '&ggps='  HDAC6  TSA    '

What I want to get from console.log would be this:

dataString:
trigger='<trigger offsetBeg="89" offsetEnd="96">induced</trigger>'&ggps='<ggps>
<ggp role="Theme" offsetBeg="68" offsetEnd="73"id="10013"consensusName="HDAC6">
HDAC6</ggp><ggp role="Cause" offsetBeg="100" offsetEnd="103" id="7001" 
consensusName="TSA">TSA</ggp></ggps>'

I want this, because I want to be able to drop these nodes directly into another XML document that I'll be building.

ems
  • 722
  • 1
  • 9
  • 16
  • I'm not clear how and when you're actually applying the XSLT, and exactly what's going on here, but it seems like you're calling `.val()` to get the value of a form input, when what you actually want is a whole element of some sort? Or maybe that *is* the value, but there's some escaping issues because of XML and HTML having shared syntax? – IMSoP Nov 16 '13 at 21:46
  • My idea was to make the value of input.trigger equal to '``'. But yeah, I think the problem has something to do with character escaping issues. – ems Nov 16 '13 at 21:51
  • Using `xsl:copy-of` and then trying to stick that into an attribute is only going to give you the text values. Have you tried running just the XSLT to see what your resulting HTML looks like? – Daniel Haley Nov 16 '13 at 22:05
  • Right, I only get the attribute text value for the form attribute. Though the `` gives the correct output when placed elsewhere in the file (see comment added above). – ems Nov 16 '13 at 22:23

1 Answers1

3

Your variable $trigger contains a full copy of the relevant tree, but when you use an attribute value template like this:

value="{$trigger}"

the value is flattened to a string - specifically, the string value of the root element, which is the concatenation of its descendant text nodes.

If you want the attribute to contain a serialised version of the tree (that is, lexical XML including markup, presumably escaped to make it a legal attribute value), then you need to invoke some kind of serialize-xml() function. There is such a function in XSLT 3.0, and in some products such as Saxon; or you could write your own.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Thanks. I'm unfamiliar with xml serialization, but this sounds like what I need. I'm new to this stuff, so I'm not sure how to tell whether I'm using XSLT 3.0 or not. Also, if you could point me to some documentation of the serialize-xml() function in XSLT 3.0, that would be helpful. Nothing obvious turned up in a quick Google search. – ems Nov 16 '13 at 23:10
  • I think you should take a look at http://stackoverflow.com/questions/6696382. The answer by @FrançoisDispaux contains a serializer that is proabably able to handle a serialization of a node set as complex as shown in your example. – Marcus Rickert Nov 16 '13 at 23:13