XML to list and back to XML - r

Situation: "Software" to R and back to "Software". The only interface for "Software" is xml.
In R, I need to make a few changes in the file so i convert it to a list and make some changes.
library(XML)
myFile = xmlParse("myXML")
xml_data <- xmlToList(myFile)
xml_data$timetable$train$.attrs[6] = "HelloNewWorld"
Now i need to convert this list "xml_data" it back to xml.
I found some functions like this:
function(item, tag) {
# just a textnode, or empty node with attributes
if(typeof(item) != 'list') {
if (length(item) > 1) {
xml <- xmlNode(tag)
for (name in names(item)) {
xmlAttrs(xml)[[name]] <- item[[name]]
}
return(xml)
} else {
return(xmlNode(tag, item))
}
}
# create the node
if (identical(names(item), c("text", ".attrs"))) {
# special case a node with text and attributes
xml <- xmlNode(tag, item[['text']])
} else {
# node with child nodes
xml <- xmlNode(tag)
for(i in 1:length(item)) {
if (names(item)[i] != ".attrs") {
xml <- append.xmlNode(xml, listToXml(item[[i]], names(item)[i]))
}
}
}
# add attributes to node
attrs <- item[['.attrs']]
for (name in names(attrs)) {
xmlAttrs(xml)[[name]] <- attrs[[name]]
}
return(xml)
}
But this doesnt work...
Any help or hints appreciated!
Thanks!
In the linked picture you can see the current xml-file. Highlighted in yellow the values that I need to change.
Link:
https://i.stack.imgur.com/remzj.png

Consider XSLT, the special-purpose language designed to transform XML files. No need to rewrite the entire tree in R. Using its xslt package (available on CRAN-R), extension of xml2, you can transform an input source and write output to screen or file.
Using the Identity Transform to copy document as is, below XSLT then rewrites one of the attributes in <train> tag, #source, similar to your above code attempt but with sixth attribute.
XML (sample input from railIML Wiki page)
<?xml version="1.0" encoding="UTF-8"?>
<railml xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" xsi:noNamespaceSchemaLocation="timetable.xsd">
<timetable version="1.1">
<train trainID="RX 100.2" type="planned" source="opentrack">
<timetableentries>
<entry posID="ZU" departure="06:08:00" type="begin"/>
<entry posID="ZWI" departure="06:10:30" type="pass"/>
<entry posID="ZOER" arrival="06:16:00" departure="06:17:00" minStopTime="9" type="stop"/>
<entry posID="WS" departure="06:21:00" type="pass"/>
<entry posID="DUE" departure="06:23:00" type="pass"/>
<entry posID="SCW" departure="06:27:00" type="pass"/>
<entry posID="NAE" departure="06:29:00" type="pass"/>
<entry posID="UST" arrival="06:34:30" type="stop"/>
</timetableentries>
</train>
</timetable>
</railml>
XSLT (save as .xsl file, rewrites the #source attribute)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#source">
<xsl:attribute name="source">HelloNewWorld</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
R
library(xslt)
doc <- read_xml("/path/to/Input.xml", package = "xslt")
style <- read_xml("/path/to/XLSTScript.xsl", package = "xslt")
new_xml <- xml_xslt(doc, style)
# OUTPUT TO SCREEN
cat(as.character(new_xml))
# OUTPUT TO FILE
write_xml(new_xml, "/path/to/Output.xml")
Output
<?xml version="1.0" encoding="UTF-8"?>
<railml xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance" xsi:noNamespaceSchemaLocation="timetable.xsd">
<timetable version="1.1">
<train trainID="RX 100.2" type="planned" source="HelloNewWorld">
<timetableentries>
<entry posID="ZU" departure="06:08:00" type="begin"/>
<entry posID="ZWI" departure="06:10:30" type="pass"/>
<entry posID="ZOER" arrival="06:16:00" departure="06:17:00" minStopTime="9" type="stop"/>
<entry posID="WS" departure="06:21:00" type="pass"/>
<entry posID="DUE" departure="06:23:00" type="pass"/>
<entry posID="SCW" departure="06:27:00" type="pass"/>
<entry posID="NAE" departure="06:29:00" type="pass"/>
<entry posID="UST" arrival="06:34:30" type="stop"/>
</timetableentries>
</train>
</timetable>
</railml>

I found it hard to apply many of the answers listed here so I wonder if this set of simple Java XML XPathHelper Unities may help others. You can find the source code here. I didn't write it all myself but adapted code I found, so I can't take all the credit but it works and it is compact and hope it helps others.
String xmlPayLoad = readFileAsString(payLoadPath + "/payLoad.xml");
TreeMap<String, String> header = new TreeMap<String, String>();
XPathHelperCommon xph = new XPathHelperCommon();
header = xph.findMultipleXMLItems(xmlPayLoad, "//header/*");
header.put("type", "newProcess");
xmlPayLoad = xph.modifyMultipleXMLItems(xmlPayLoad, "//header/*", header);
The primative XML header could be something like this:
<header>
<type>process</type>
<ruleBaseVersion>0</ruleBaseVersion>
<ruleBaseCommitment>0</ruleBaseCommitment>
<sequenceId>0</sequenceId>
<priortiseSID>0</priortiseSID>
<monitorIncomingEvents>0</monitorIncomingEvents>
<activityCount>0</activityCount>
<taskElapsedTime>0</taskElapsedTime>
<processStartTime>0</processStartTime>
<processElapsedTime>0</processElapsedTime>
<eventElapsedTime>0</eventElapsedTime>
<status>0</status>
</header>

Related

Convert in R a XML with ASCII Entity Names to a basic XML

I have the following XML file:
<?xpacket begin="???" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.4-c006 80.159825, 2016/09/16-03:31:08 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:pdfx="http://ns.adobe.com/pdfx/1.3/"
xmlns:pdf="http://ns.adobe.com/pdf/1.3/"
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmlns:pdfx_1_="ns.adobe.org/pdfx/1.3/">
<xmp:CreateDate>2021-05-30T11:17:35+02:00</xmp:CreateDate>
<xmp:CreatorTool>TeX</xmp:CreatorTool>
<xmp:ModifyDate>2021-05-30T12:12:25+02:00</xmp:ModifyDate>
<xmp:MetadataDate>2021-05-30T12:12:25+02:00</xmp:MetadataDate>
<pdfx:PTEX.Fullbanner>This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) kpathsea version 6.3.1</pdfx:PTEX.Fullbanner>
<pdf:Producer>pdfTeX-1.40.20</pdf:Producer>
<pdf:Trapped>Unknown</pdf:Trapped>
<pdf:Keywords/>
<dc:format>application/pdf</dc:format>
<xmpMM:DocumentID>uuid:38d0617c-0385-5941-a87d-cc4a1e54bd76</xmpMM:DocumentID>
<xmpMM:InstanceID>uuid:d056c61c-55c6-5f44-8c0e-fe6e911c2ed9</xmpMM:InstanceID>
<pdfwe:dafra>
<?xml version="1.0"?>
<dataframe name="expData"
xmlns="url"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="url">
<column name="DATA" type="ratio">
<value>14</value>
<value>18</value>
<value>21</value>
<value>35</value>
<value>44</value>
<value>50</value>
<value>3</value>
<value>5</value>
<value>7</value>
</column>
</dataframe>
</pdfx_1_:Dataframe>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
As you can see, the tag Dataframe of the namespace pdfwe have inside it another XML. I need to extract this XML and convert it to a normal XML with no ASCII Entity Names like the following:
<?xml version="1.0"?>
<dataframe name="expData"
xmlns="url"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="url">
<column name="DATA" type="ratio">
<value>14</value>
<value>18</value>
<value>21</value>
<value>35</value>
<value>44</value>
<value>50</value>
<value>3</value>
<value>5</value>
<value>7</value>
</column>
</dataframe>
To extract what's inside pdfwe:dafra I'm using the function xml_find_all(x, ".//pdfwe:dafra") of the xml2 package but I'm not getting the result I want.
To convert the Entity Names I'm using the function xml2::xml_text(xml2::read_xml(paste0("<x>", md, "</x>"))) but I'm not getting the results I want either.
Thanks in advance!
The solution is a multi step process, extract the database node, convert to text, clean up and then convert back to xml with the read_xml() function.
library(xml2)
page <- read_xml('<?xpacket begin="???" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.4-c006 80.159825, 2016/09/16-03:31:08">
.....') #read in the entire file
xml_ns(page) #show namespaces
#extract the database
db <- xml_find_first(page, ".//pdfx_1_:Dataframe")
#convert to text and strip leading whitespace
dbtext <- xml_text(db) %>% trimws()
#read the text in and convert to xml
xml_db <- read_xml(dbtext)
xml_ns(xml_db) #show namespaces
#extract the requested information from database
#shown here for demonstration purposes
xml_db %>% xml_find_all(".//d1:column") %>% xml_find_all(".//d1:value") %>% xml_text()

Parse HTML/XML characters in R

I am reading in the following XML as a text file in R:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE score-partwise PUBLIC
"-//Recordare//DTD MusicXML 3.0 Partwise//EN"
"http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="3.0">
<part-list>
<score-part id="P1">
<part-name>Music</part-name>
</score-part>
</part-list>
<part id="P1">
<measure number="1">
<attributes>
<divisions>1</divisions>
<key>
<fifths>0</fifths>
</key>
<time>
<beats>4</beats>
<beat-type>4</beat-type>
</time>
<clef>
<sign>G</sign>
<line>2</line>
</clef>
</attributes>
<note>
<pitch>
<step>C</step>
<octave>4</octave>
</pitch>
<duration>4</duration>
<type>whole</type>
</note>
</measure>
</part>
</score-partwise>
R:
library(readtext)
xml <- readtext("musicxml.txt")$text
I am then trying to render this in Javascript via Shiny by feeding my XML text to a Javascript function. NB: Working outside of R.
shiny::tags$script(paste0('var osmd = new opensheetmusicdisplay.OpenSheetMusicDisplay(\"sheet-music\", {drawingParameters: "compact",
drawPartNames: false, drawMeasureNumbers: false, drawMetronomeMarks: false, drawTitle: false});
var loadPromise = osmd.load(\'',xml,'\');
loadPromise.then(function(){
osmd.render();
});
'))
However, when I concatenate the XML string above, it does not work because characters are escaped, e.g one line:
<note>
I tried using the unescape_xml function here (with and without the tags removed), but this does not solve the problem. It leaves me with:
"Music1044G2C44whole"
So how can I end up with a concatenated string with none of the escaped characters? It must just be a string and not another R object.
You need to wrap the contents of the tag call with shiny::HTML to ensure it is passed unescaped:
shiny::tags$script(shiny::HTML(paste0(
'var osmd = new opensheetmusicdisplay.OpenSheetMusicDisplay(\"sheet-music\",
{ drawingParameters: "compact",
drawPartNames: false,
drawMeasureNumbers: false,
drawMetronomeMarks: false,
drawTitle: false});
var loadPromise = osmd.load(\'',xml,'\');
loadPromise.then(function(){ osmd.render() });')))
Which gives you:
<script>var osmd = new opensheetmusicdisplay.OpenSheetMusicDisplay("sheet-music",
{ drawingParameters: "compact",
drawPartNames: false,
drawMeasureNumbers: false,
drawMetronomeMarks: false,
drawTitle: false});
var loadPromise = osmd.load('<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE score-partwise PUBLIC
"-//Recordare//DTD MusicXML 3.0 Partwise//EN"
"http://www.musicxml.org/dtds/partwise.dtd">
<score-partwise version="3.0">
<part-list>
<score-part id="P1">
<part-name>Music</part-name>
</score-part>
</part-list>
<part id="P1">
<measure number="1">
<attributes>
<divisions>1</divisions>
<key>
<fifths>0</fifths>
</key>
<time>
<beats>4</beats>
<beat-type>4</beat-type>
</time>
<clef>
<sign>G</sign>
<line>2</line>
</clef>
</attributes>
<note>
<pitch>
<step>C</step>
<octave>4</octave>
</pitch>
<duration>4</duration>
<type>whole</type>
</note>
</measure>
</part>
</score-partwise>');
loadPromise.then(function(){ osmd.render() });</script>

Import XML to R data frame

I am trying to import an xml file into R. It is of the format below with an event on each row followed by a number of attributes - which ones depend on the event type. This file is 0.7GB and future versions may be much bigger. I would like to create a data frame with each event on a new row and all the possible attributes in separate columns (meaning some will be empty depending on the event type). I have looked elsewhere for answers but they all seem to be dealing with XML files in a tree structure and I can't work out how to apply them to this format.
I am new to R and have no experience with XML files so please give me the "for dummies" answer with plenty of explanation. Thanks!
<?xml version="1.0" encoding="utf-8"?>
<events version="1.0">
<event time="21510.0" type="actend" person="3" link="1" actType="h" />
<event time="21510.0" type="departure" person="3" link="1" legMode="car" />
<event time="21510.0" type="PersonEntersVehicle" person="3" vehicle="3" />
<event time="21510.0" type="vehicle enters traffic" person="3" link="1" vehicle="3" networkMode="car" relativePosition="1.0" />
...
</events>
You can try something like this:
original_xml <- '<?xml version="1.0" encoding="utf-8"?>
<events version="1.0">
<event time="21510.0" type="actend" person="3" link="1" actType="h" />
<event time="21510.0" type="departure" person="3" link="1" legMode="car" />
<event time="21510.0" type="PersonEntersVehicle" person="3" vehicle="3" />
<event time="21510.0" type="vehicle enters traffic" person="3" link="1" vehicle="3" networkMode="car" relativePosition="1.0" />
</events>'
library(xml2)
data2 <- xml_children(read_xml(original_xml))
attr_names <- unique(names(unlist(xml_attrs(data2))))
xmlDataFrame <- as.data.frame(sapply(attr_names, function (attr) {
xml_attr(data2, attr = attr)
}), stringsAsFactors = FALSE)
#-- since all columns are strings, you may want to turn the numeric columns to numeric
xmlDataFrame[, c("time", "person", "link", "vehicle")] <- sapply(xmlDataFrame[, c("time", "person", "link", "vehicle")], as.numeric)
If you have additional "numeric" columns, you can add them at the end to convert the data to its proper class.

Add children to existing node using R XML

I have the following XML file test.graphml that I am trying to manipulate using the XML package in R.
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<graph id="G" edgedefault="directed">
<node id="n0"/>
<node id="n1"/>
<node id="n2"/>
<node id="n3"/>
<node id="n4"/>
<edge source="n0" target="n1"/>
<edge source="n0" target="n2"/>
<edge source="n2" target="n3"/>
<edge source="n1" target="n3"/>
<edge source="n3" target="n4"/>
</graph>
</graphml>
I would like to nest nodes n0, n1, n2, and n3 into a new graph node as shown below.
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<graph id="G" edgedefault="directed">
<graph id="g1">
<node id="n0"/>
<node id="n1"/>
<node id="n2"/>
<node id="n3"/>
</graph>
<node id="n4"/>
<edge source="n0" target="n1"/>
<edge source="n0" target="n2"/>
<edge source="n2" target="n3"/>
<edge source="n1" target="n3"/>
<edge source="n3" target="n4"/>
</graph>
</graphml>
The code I have written has unknowns and errors that I am unable to resolve due to lack of experience with XML processing. I would greatly appreciate some pointers to that will help me proceed.
library(XML)
# Read file
x <- xmlParse("test.graphml")
ns <- c(graphml ="http://graphml.graphdrawing.org/xmlns")
# Create new graph node
ng <- xmlNode("graph", attrs = c("id" = "g1"))
# Add n0-n3 as children of new graph node
n0_n1_n2_n3 <- getNodeSet(x,"//graphml:node[#id = 'n0' or #id='n1' or #id='n2' or #id='n3']", namespaces = ns)
ng <- append.xmlNode(ng, n0_n1_n2_n3)
# Get only graph node
g <- getNodeSet(x,"//graphml:graph", namespaces = ns)
# Remove nodes n0-n3 from the only graph node
# How I do this?
# This did not work: removeNodes(g, n0_n1_n2_n3)
# Add new graph node as child of only graph node
g <- append.xmlNode(g, ng)
#! Error message:
Error in UseMethod("append") :
no applicable method for 'append' applied to an object of class "XMLNodeSet"
Consider XSLT, the special-purpose language to transform XML files. Since you require modification of the XML (adding parent node in a select group of children) and have to navigate through an undeclared namespace prefix (xmlns="http://graphml.graphdrawing.org/xmlns"), XSLT is an optimal solution.
However, to date R does not have a fully compliant XSL module to run XSLT 1.0 scripts like other general purpose languages (Java, PHP, Python). Nonetheless, R can call external programs (including aforementioned languages), or dedicated XSLT processors (Xalan, Saxon), or call command line interpreters including PowerShell and terminal's xsltproc using system(). Below are latter solutions.
XSLT (save as .xsl, to be referenced in R script)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:doc="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="doc:graphml">
<xsl:copy>
<xsl:copy-of select="document('')/*/#xsi:schemaLocation"/>
<xsl:apply-templates select="doc:graph"/>
</xsl:copy>
</xsl:template>
<xsl:template match="doc:graph">
<xsl:element name="{local-name()}" namespace="http://graphml.graphdrawing.org/xmlns">
<xsl:apply-templates select="#*"/>
<xsl:element name="graph" namespace="http://graphml.graphdrawing.org/xmlns">
<xsl:attribute name="id">g1</xsl:attribute>
<xsl:apply-templates select="doc:node[position() < 5]"/>
</xsl:element>
<xsl:apply-templates select="doc:node[#id='n4']|doc:edge"/>
</xsl:element>
</xsl:template>
<xsl:template match="doc:graph/#*">
<xsl:attribute name="{local-name()}"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
<xsl:template match="doc:node|doc:edge">
<xsl:element name="{local-name()}" namespace="http://graphml.graphdrawing.org/xmlns">
<xsl:attribute name="{local-name(#*)}"><xsl:value-of select="#*"/></xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
PowerShell script (for Windows PC users, save as XMLTransform.ps1)
param ($xml, $xsl, $output)
if (-not $xml -or -not $xsl -or -not $output) {
Write-Host "& .\xslt.ps1 [-xml] xml-input [-xsl] xsl-input [-output] transform-output"
exit;
}
trap [Exception]{
Write-Host $_.Exception;
}
$xslt = New-Object System.Xml.Xsl.XslCompiledTransform;
$xslt.Load($xsl);
$xslt.Transform($xml, $output);
Write-Host "generated" $output;
R Script (calling command line operations)
library(XML)
# WINDOWS USERS
ps <- '"C:\\Path\\To\\XMLTransform.ps1"' # POWER SHELL SCRIPT
input <- '"C:\\Path\\To\\Input.xml"' # XML SOURCE
xsl <- '"C:\\Path\\To\\XSLTScript.xsl"' # XSLT SCRIPT
output <- '"C:\\Path\\To\\Output.xml"' # BLANK, EMPTY FILE PATH TO BE CREATED
system(paste('Powershell.exe -executionpolicy remotesigned -File',
ps, input, xsl, output)) # NOTE SECURITY BYPASS ARGS
doc <- xmlParse("C:\\Path\\To\\Output.xml")
# UNIX (MAC/LINUX) USERS
system("xsltproc /path/to/XSLTScript.xsl /path/to/input.xml -o /path/to/output.xml")
doc <- xmlParse("/path/to/output.xml")
print(doc)
# <?xml version="1.0" encoding="utf-8"?>
# <graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
# <graph id="G" edgedefault="directed">
# <graph id="g1">
# <node id="n0"/>
# <node id="n1"/>
# <node id="n2"/>
# <node id="n3"/>
# </graph>
# <node id="n4"/>
# <edge source="n0"/>
# <edge source="n0"/>
# <edge source="n2"/>
# <edge source="n1"/>
# <edge source="n3"/>
# </graph>
# </graphml>

XSLT : Cannot convert the operand to 'Result tree fragment'

I work on an xslt stylesheet, and I should receive as parameter two additional XML. I get an error when I use the node-set() method (from namespace ms, microsoft). The contents of the XML is correct. The parameters are send with classic ASP.
Here's the header and the call in xslt:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
...
<xsl:param name="xmlPlanning"></xsl:param>
<xsl:variable name="myXml" select="ms:node-set($xmlPlanning)"></xsl:variable>
<xsl:value-of select="ms:node-set($xmlPlanning)/*"/>
Here's the stack trace of the error:
[XsltException: Impossible de convertir l'opérande en 'fragment de l'arborescence résultat'.]
System.Xml.Xsl.XsltOld.XsltFunctionImpl.ToNavigator(Object argument) +380943
System.Xml.Xsl.XsltOld.FuncNodeSet.Invoke(XsltContext xsltContext, Object[] args, XPathNavigator docContext) +33
MS.Internal.Xml.XPath.FunctionQuery.Evaluate(XPathNodeIterator nodeIterator) +292
[XPathException: Échec de la fonction 'ms:node-set()'.]
MS.Internal.Xml.XPath.FunctionQuery.Evaluate(XPathNodeIterator nodeIterator) +347
System.Xml.Xsl.XsltOld.Processor.RunQuery(ActionFrame context, Int32 key) +24
System.Xml.Xsl.XsltOld.VariableAction.Execute(Processor processor, ActionFrame frame) +200
System.Xml.Xsl.XsltOld.ActionFrame.Execute(Processor processor) +20
System.Xml.Xsl.XsltOld.Processor.Execute() +82
System.Xml.Xsl.XsltOld.Processor.Execute(TextWriter writer) +96
System.Xml.Xsl.XslTransform.Transform(XPathNavigator input, XsltArgumentList args, TextWriter output, XmlResolver resolver) +68
System.Xml.Xsl.XslTransform.Transform(IXPathNavigable input, XsltArgumentList args, TextWriter output, XmlResolver resolver) +43
System.Web.UI.WebControls.Xml.Render(HtmlTextWriter output) +132
And here's the beginning of the xml I receive in parameter :
<?xml version="1.0" encoding="UTF-8"?>
<ArrayOfGenerationPlanningDesign xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://webservices.secureholiday.net/">
<GenerationPlanningDesign>
What could be my problem ?
In case the parameter you are passing is already a true nodeset (XPath navigator or XPathNodeIterator in .NET or IXMLDOMNodeList for MSXML), you don't need and must not use the ms:node-set() extension function. Simply remove the call to ms:nodeset().
In case it is a string that represents XML -- well it shouldn't! Parse this string to one of the allowable parameter types for a nodeset and only then invoke the transformation -- using the true node-set.
node-set() operates on Result Document Fragments (RDFs) only, but you give it a string, which is something entirely different (even if the string contents looks like XML).
What you must do is parse the string into XML. You can use an extension script for that. The following worked for me (tested with msxsl.exe on the command line), but if you don't want to use JScript you can use C# or any other supported language to do the same.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:script="urn:my-scripts"
exclude-result-prefixes="ms script"
>
<ms:script language="JScript" implements-prefix="script">
<![CDATA[
function stringToXml(str) {
var xml = new ActiveXObject("MSXML2.DOMDocument.4.0");
xml.async = false;
xml.loadXML(str);
return xml;
}
]]>
</ms:script>
<xsl:param name="xmlPlanning"></xsl:param>
<xsl:variable name="myXml" select="script:stringToXml(string($xmlPlanning))" />
<xsl:template match="/">
<xsl:value-of select="$myXml/*" /><!-- whatever -->
</xsl:template>
</xsl:stylesheet>
As Dimitre said you can use ms:node-set but you must use node()
<xsl:variable name="yourVariable">
<xsl:copy-of select="/foo/bar/something/node()"/>
</xsl:variable>
<xsl:value-of select="ms:node-set($yourVariable)/theOtherElement"/>

Resources