XML/Output
You are encouraged to solve this task according to the task description, using any language you may know.
Create a function that takes a list of character names and a list of corresponding remarks and returns an XML document of <Character>
elements each with a name attributes and each enclosing its remarks. All <Character>
elements are to be enclosed in turn, in an outer <CharacterRemarks>
element.
As an example, calling the function with the three names of:
April Tam O'Shanter Emily
And three remarks of:
Bubbly: I'm > Tam and <= Emily Burns: "When chapman billies leave the street ..." Short & shrift
Should produce the XML (but not necessarily with the indentation):
<CharacterRemarks> <Character name="April">Bubbly: I'm > Tam and <= Emily</Character> <Character name="Tam O'Shanter" >Burns: "When chapman billies leave the street ..."</Character> <Character name="Emily">Short & shrift</Character> </CharacterRemarks>
The document may include an <?xml?> declaration and document type declaration, but these are optional. If attempting this task by direct string manipulation, the implementation must include code to perform entity substitution for the characters that have entities defined in the XML 1.0 specification.
Note: the example is chosen to show correct escaping of XML strings. Note too that although the task is written to take two lists of corresponding data, a single mapping/hash/dictionary of names to remarks is also acceptable.
Note to editors: Program output with escaped characters will be viewed as the character on the page so you need to 'escape-the-escapes' to make the RC entry display what would be shown in a plain text viewer. (See this)
AutoHotkey
<lang AutoHotkey> gosub constants names := xmlescape(names) remarks := xmlescape(remarks)
stringsplit, remarks, remarks, `n xml = "<CharacterRemarks>"
loop, parse, names, `n
xml .= "<Character name=" . A_LoopField . ">" . remarks%A_Index% . "</Character>`n"
xml .= "</CharacterRemarks>"
msgbox % xml return
xmlescape(string) {
static punc = ",>,<,<=,>=,',& ; " xmlpunc = ",>,<,<=,>=,',& if !punc1 {
StringSplit, punc, punc, `, StringSplit, xmlpunc, xmlpunc, `,
} escaped := string loop, parse, punc, `, { StringReplace, escaped, escaped, % A_LoopField, % xmlpunc%A_Index%, All } Return escaped
}
constants:
- LTrim
names = (
April Tam O'Shanter Emily
)
remarks = (
Bubbly: I'm > Tam and <= Emily Burns: "When chapman billies leave the street ..." Short & shrift
) return </lang>
BASIC
<lang basic>Data "April", "Bubbly: I'm > Tam and <= Emily", _
"Tam O'Shanter", "Burns: ""When chapman billies leave the street ...""", _ "Emily", "Short & shrift"
Declare Function xmlquote(ByRef s As String) As String Dim n As Integer, dev As String, remark As String
Print "<CharacterRemarks>" For n = 0 to 2
Read dev, remark Print " <Character name="""; xmlquote(dev); """>"; _ xmlquote(remark); "</Character>"
Next Print "</CharacterRemarks>"
End
Function xmlquote(ByRef s As String) As String
Dim n As Integer Dim r As String For n = 0 To Len(s) Dim c As String c = Mid(s,n,1) Select Case As Const Asc(c) Case Asc("<") r = r + "<" Case Asc(">") r = r + ">" Case Asc("&") r = r + "&" Case Asc("""") r = r + """ Case Asc("'") r = r + "'" Case Else r = r + c End Select Next Function = r
End Function</lang>
C
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- include <libxml/parser.h>
- include <libxml/tree.h>
const char *names[] = {
"April", "Tam O'Shanter", "Emily", NULL
}; const char *remarks[] = {
"Bubbly: I'm > Tam and <= Emily", "Burns: \"When chapman billies leave the street ...\"", "Short & shrift", NULL
};
int main() {
xmlDoc *doc = NULL; xmlNode *root = NULL, *node; const char **next; int a;
doc = xmlNewDoc("1.0"); root = xmlNewNode(NULL, "CharacterRemarks"); xmlDocSetRootElement(doc, root);
for(next = names, a = 0; *next != NULL; next++, a++) { node = xmlNewNode(NULL, "Character"); (void)xmlNewProp(node, "name", *next); xmlAddChild(node, xmlNewText(remarks[a])); xmlAddChild(root, node); }
xmlElemDump(stdout, doc, root);
xmlFreeDoc(doc); xmlCleanupParser(); return EXIT_SUCCESS;
}</lang>
Common Lisp
<lang lisp>(defun write-xml (characters lines &optional (out *standard-output*))
(let* ((doc (dom:create-document 'rune-dom:implementation nil nil nil)) (chars (dom:append-child doc (dom:create-element doc "Characters")))) (map nil (lambda (character line) (let ((c (dom:create-element doc "Character"))) (dom:set-attribute c "name" character) (dom:append-child c (dom:create-text-node doc line)) (dom:append-child chars c))) characters lines) (write-string (dom:map-document (cxml:make-rod-sink) doc) out)))</lang>
Example of use:
<lang lisp>(write-xml '("April" "Tam O'Shanter" "Emily")
'("Bubbly: I'm > Tam and <= Emily" "Burns: \"When chapman billies leave the street ...\"" "Short & shrift"))</lang>
output:
<?xml version="1.0" encoding="UTF-8"?> <Characters><Character name="April">Bubbly: I'm > Tam and <= Emily</Character><Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character><Character name="Emily">Short & shrift</Character></Characters>
D
<lang d> import kxml.xml; char[][][]characters =
[["April","Bubbly: I'm > Tam and <= Emily"], ["Tam O'Shanter","Burns: \"When chapman billies leave the street ...\""], ["Emily","Short & shrift"]];
void addChars(XmlNode root,char[][][]info) {
auto remarks = new XmlNode("CharacterRemarks"); root.addChild(remarks); foreach(set;info) { remarks.addChild((new XmlNode("Character")).setAttribute("name",set[0]).addCData(set[1])); }
} void main() {
auto root = new XmlNode(""); root.addChild(new XmlPI("xml")); addChars(root,characters); std.stdio.writefln("%s",root.write);
} </lang>
<?xml?> <CharacterRemarks> <Character name="April"> Bubbly: I'm > Tam and <= Emily </Character> <Character name="Tam O'Shanter"> Burns: "When chapman billies leave the street ..." </Character> <Character name="Emily"> Short & shrift </Character> </CharacterRemarks>
F#
#light open System.Xml type Character = {name : string; comment : string } let data = [ { name = "April"; comment = "Bubbly: I'm > Tam and <= Emily"} { name = "Tam O'Shanter"; comment = "Burns: \"When chapman billies leave the street ...\""} { name = "Emily"; comment = "Short & shrift"} ] let doxml (characters : Character list) = let doc = new XmlDocument() let root = doc.CreateElement("CharacterRemarks") doc.AppendChild root |> ignore Seq.iter (fun who -> let node = doc.CreateElement("Character") node.SetAttribute("name", who.name) doc.CreateTextNode(who.comment) |> node.AppendChild |> ignore root.AppendChild node |> ignore ) characters doc.OuterXml
<CharacterRemarks> <Character name="April">Bubbly: I'm > Tam and <= Emily</Character> <Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character> <Character name="Emily">Short & shrift</Character> </CharacterRemarks>
Haskell
This implementation uses the xml
package.
<lang haskell>import Text.XML.Light
characterRemarks :: [String] -> [String] -> String characterRemarks names remarks = showElement $ Element
(unqual "CharacterRemarks") [] (zipWith character names remarks) Nothing where character name remark = Elem $ Element (unqual "Character") [Attr (unqual "name") name] [Text $ CData CDataText remark Nothing] Nothing</lang>
Java
Using DOM
<lang java> import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document; import org.w3c.dom.Element;
public class XmlCreation {
private static final String[] names = {"April", "Tam O'Shanter", "Emily"}; private static final String[] remarks = {"Bubbly: I'm > Tam and <= Emily", "Burns: \"When chapman billies leave the street ...\"", "Short & shrift"}; public static void main(String[] args) { try { // Create a new XML document final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); // Append the root element final Element root = doc.createElement("CharacterRemarks"); doc.appendChild(root); // Read input data and create a new <Character> element for each name. for(int i = 0; i < names.length; i++) { final Element character = doc.createElement("Character"); root.appendChild(character); character.setAttribute("name", names[i]); character.appendChild(doc.createTextNode(remarks[i])); } // Serializing XML in Java is unnecessary complicated // Create a Source from the document. final Source source = new DOMSource(doc); // This StringWriter acts as a buffer final StringWriter buffer = new StringWriter(); // Create a Result as a transformer target. final Result result = new StreamResult(buffer); // The Transformer is used to copy the Source to the Result object. final Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty("indent", "yes"); transformer.transform(source, result); // Now the buffer is filled with the serialized XML and we can print it // to the console. System.out.println(buffer.toString()); } catch (Exception e) { e.printStackTrace(); } }
} </lang>
Result:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <CharacterRemarks> <Character name="April">Bubbly: I'm > Tam and <= Emily</Character> <Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character> <Character name="Emily">Short & shrift</Character>
Using the Streaming API for XML (StAX)
<lang java> import java.io.StringWriter;
import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamWriter;
public class XmlCreationStax {
private static final String[] names = {"April", "Tam O'Shanter", "Emily"}; private static final String[] remarks = {"Bubbly: I'm > Tam and <= Emily", "Burns: \"When chapman billies leave the street ...\"", "Short & shrift"}; public static void main(String[] args) { try { final StringWriter buffer = new StringWriter(); final XMLStreamWriter out = XMLOutputFactory.newInstance() .createXMLStreamWriter(buffer);
out.writeStartDocument("UTF-8", "1.0"); out.writeStartElement("CharacterRemarks"); for(int i = 0; i < names.length; i++) { out.writeStartElement("Character"); out.writeAttribute("name", names[i]); out.writeCharacters(remarks[i]); out.writeEndElement(); } out.writeEndElement(); out.writeEndDocument(); System.out.println(buffer); } catch (Exception e) { e.printStackTrace(); } }
} </lang>
This produces:
<?xml version="1.0" encoding="UTF-8"?><CharacterRemarks><Character name="April">Bubbly: I'm > Tam and <= Emily</Character><Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character><Character name="Emily">Short & shrift</Character></CharacterRemarks>
OCaml
<lang ocaml>
- #directory "+xml-light" (* or maybe "+site-lib/xml-light" *) ;;
- #load "xml-light.cma" ;;
- let data = [
("April", "Bubbly: I'm > Tam and <= Emily"); ("Tam O'Shanter", "Burns: \"When chapman billies leave the street ...\""); ("Emily", "Short & shrift"); ] in let tags = List.map (fun (name, comment) -> Xml.Element ("Character", [("name", name)], [(Xml.PCData comment)]) ) data in print_endline ( Xml.to_string_fmt (Xml.Element ("CharacterRemarks", [], tags))) ;;
<CharacterRemarks>
<Character name="April">Bubbly: I'm > Tam and <= Emily</Character> <Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character> <Character name="Emily">Short & shrift</Character>
</CharacterRemarks> - : unit = () </lang>
Perl
<lang perl>#! /usr/bin/perl use strict; use XML::Mini::Document;
my @students = ( [ "April", "Bubbly: I'm > Tam and <= Emily" ],
[ "Tam O'Shanter", "Burns: \"When chapman billies leave the street ...\"" ],
[ "Emily", "Short & shrift" ]
);
my $doc = XML::Mini::Document->new(); my $root = $doc->getRoot(); my $studs = $root->createChild("CharacterRemarks"); foreach my $s (@students) {
my $stud = $studs->createChild("Character"); $stud->attribute("name", $s->[0]); $stud->text($s->[1]);
} print $doc->toString();</lang>
Python
Normal output is all one line of XML, the .replace(...) makes it more readable. <lang python>>>> from xml.etree import ElementTree as ET >>> from itertools import izip >>> def characterstoxml(names, remarks): root = ET.Element("CharacterRemarks") for name, remark in izip(names, remarks): c = ET.SubElement(root, "Character", {'name': name}) c.text = remark return ET.tostring(root)
>>> print characterstoxml( names = ["April", "Tam O'Shanter", "Emily"], remarks = [ "Bubbly: I'm > Tam and <= Emily", 'Burns: "When chapman billies leave the street ..."', 'Short & shrift' ] ).replace('><','>\n<')</lang> Gives the output:
<CharacterRemarks> <Character name="April">Bubbly: I'm > Tam and <= Emily</Character> <Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character> <Character name="Emily">Short & shrift</Character> </CharacterRemarks>
R
<lang R> library(XML) char2xml <- function(names, remarks){ tt <- xmlHashTree() head <- addNode(xmlNode("CharacterRemarks"), character(), tt) node <- list() for (i in 1:length(names)){ nodei <- addNode(xmlNode("Character", attrs=c(name=names[i])), head, tt) addNode(xmlTextNode(remarks[i]), nodei, tt) } return(tt) } output <- char2xml( names=c("April","Tam O'Shanter","Emily"), remarks=c("Bubbly: I'm > Tam and <= Emily", 'Burns: "When chapman billies leave the street ..."', "Short & shrift") )</lang>
Gives the output:
<CharacterRemarks> <Character name="April">Bubbly: I'm > Tam and <= Emily</Character> <Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character> <Character name="Emily">Short & shrift</Character> </CharacterRemarks>
Ruby
The
library handles character mapping when adding attributes and text.
<lang ruby>require 'rexml/document' include REXML
remarks = {
%q(April) => %q(Bubbly: I'm > Tam and <= Emily), %q(Tam O'Shanter) => %q(Burns: "When chapman billies leave the street ..."), %q(Emily) => %q(Short & shrift),
}
doc = Document.new root = doc.add_element("CharacterRemarks")
remarks.each do |name, remark|
root.add_element("Character", {'Name' => name}).add_text(remark)
end
- output with indentation
doc.write($stdout, 2)</lang>
produces
<CharacterRemarks> <Character Name='Emily'> Short & shrift </Character> <Character Name='Tam O'Shanter'> Burns: "When chapman billies leave the street ..." </Character> <Character Name='April'> Bubbly: I'm > Tam and <= Emily </Character> </CharacterRemarks>
Slate
<lang slate>
lobby define: #remarks -> ( {'April' -> 'Bubbly: I\'m > Tam and <= Emily'. 'Tam O\'Shanter' -> 'Burns: "When chapman billies leave the street ..."'. 'Emily' -> 'Short & shrift'. } as: Dictionary).
define: #writer -> (Xml Writer newOn: new writer). writer inTag: 'CharacterRemarks' do:
[| :w | lobby remarks keysAndValuesDo: [| :name :remark | w inTag: 'Character' do: [| :w | w ; remark] &attributes: {'name' -> name}]. ].
inform: writer contents </lang>
Produces:
<CharacterRemarks><Character name="Emily">Short & shrift</Character><Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character><Character name="April">Bubbly: I'm > Tam and <= Emily</Character></CharacterRemarks>
Tcl
Using only Tcl string manipulation
<lang Tcl>proc xquote string {
list [string map {' ' \" " < > > < & &} $string]
} proc < {name attl args} {
set res <$name foreach {att val} $attl { append res " $att='$val'" } if {[llength $args]} { append res > set sep "" foreach a $args { append res $sep $a set sep \n } append res </$name> } else {append res />} return $res
} set cmd {< CharacterRemarks {}} foreach {name comment} {
April "Bubbly: I'm > Tam and <= Emily" "Tam O'Shanter" "Burns: \"When chapman billies leave the street ...\"" Emily "Short & shrift"
} {
append cmd " \[< Character {Name [xquote $name]} [xquote $comment]\]"
} puts [eval $cmd]</lang>
produces
<CharacterRemarks><Character Name='April'>Bubbly: I'm < Tam and >= Emily</Character> <Character Name='Tam O'Shanter'>Burns: "When chapman billies leave the street ..."</Character> <Character Name='Emily'>Short & shrift</Character></CharacterRemarks>
Working with DOM trees
Using
<lang tcl>package require tdom set xml [dom createDocument CharacterRemarks] foreach {name comment} {
April "Bubbly: I'm > Tam and <= Emily" "Tam O'Shanter" "Burns: \"When chapman billies leave the street ...\"" Emily "Short & shrift"
} {
set elem [$xml createElement Character] $elem setAttribute name $name $elem appendChild [$xml createTextNode $comment] [$xml documentElement] appendChild $elem
} $xml asXML</lang>
<CharacterRemarks> <Character name="April">Bubbly: I'm &gt; Tam and &lt;= Emily</Character> <Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character> <Character name="Emily">Short & shrift</Character> </CharacterRemarks>
Using
<lang tcl>package require dom set xml [dom::DOMImplementation create] set root [dom::document createElement $xml CharacterRemarks] foreach {name comment} {
April "Bubbly: I'm > Tam and <= Emily" "Tam O'Shanter" "Burns: \"When chapman billies leave the street ...\"" Emily "Short & shrift"
} {
set element [dom::document createElement $root Character] dom::element setAttribute $element name $name dom::document createTextNode $element $comment
} dom::DOMImplementation serialize $xml -indent 1</lang> produces (with line breaks added for clarity:
<?xml version="1.0"?> <CharacterRemarks> <Character name="April">Bubbly: I'm > Tam and <= Emily</Character> <Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..."</Character> <Character name="Emily">Short & shrift</Character> </CharacterRemarks>
Vedit macro language
The input data is given in an edit buffer, one name+remark pair on each line line, separated with TAB character. <lang vedit> // Replace special characters with entities: Replace("&", "&", BEGIN+ALL+NOERR) // this must be the first replace! Replace("<", "<", BEGIN+ALL+NOERR) Replace(">", ">", BEGIN+ALL+NOERR) Replace("'", "'", BEGIN+ALL+NOERR) Replace('"', """, BEGIN+ALL+NOERR)
// Insert XML marking BOF IT("<CharacterRemarks>") IN Repeat(ALL) {
Search("^.", REGEXP+ERRBREAK) IT(' <Character name="') Replace('|T', '">') EOL IT('</Character>')
} EOF IT("</CharacterRemarks>") IN </lang>
Example input:
April Bubbly: I'm > Tam and <= Emily Tam O'Shanter Burns: "When chapman billies leave the street ..." Emily Short & shrift
Produces this output:
<CharacterRemarks> <Character name="April">Bubbly: I'm > Tam and <= Emily</Character> <Character name="Tam O'Shanter">Burns: "When chapman billies leave the street ..." </Character> <Character name="Emily">Short & shrift</Character> </CharacterRemarks>
Visual Basic .NET
<lang vbnet>Dim names As String() = New String() {"April", "Bob", "Chad", "Dave", "Emily"}
Dim xml = <Students>
<%= From s In names Select <Student Name=<%= s %>/> %> </Students>
Console.WriteLine(xml)</lang>