2 using System
.Collections
;
10 public class RdfXmlWriter
: RdfWriter
{
16 Hashtable nodeMap
= new Hashtable();
19 Hashtable anonAlloc
= new Hashtable();
21 public RdfXmlWriter(string file
) : this(file
, null) { }
23 public RdfXmlWriter(string file
, NamespaceManager ns
) : this(GetWriter(file
), ns
) { }
25 public RdfXmlWriter(TextWriter writer
) : this(writer
, null) { }
27 public RdfXmlWriter(TextWriter writer
, NamespaceManager ns
) : this(NewWriter(writer
), ns
) { }
29 private static XmlWriter
NewWriter(TextWriter writer
) {
30 XmlTextWriter ret
= new XmlTextWriter(writer
);
31 ret
.Formatting
= Formatting
.Indented
;
33 ret
.IndentChar
= '\t';
34 ret
.Namespaces
= true;
38 public RdfXmlWriter(XmlWriter writer
) : this(writer
, null) { }
40 public RdfXmlWriter(XmlWriter writer
, NamespaceManager ns
) {
42 ns
= new NamespaceManager();
47 private void Start() {
48 if (doc
!= null) return;
49 doc
= new XmlDocument();
51 string rdfprefix
= ns
.GetPrefix(NS
.RDF
);
52 if (rdfprefix
== null) {
53 if (ns
.GetNamespace("rdf") == null) {
55 ns
.AddNamespace(NS
.RDF
, "rdf");
59 XmlElement root
= doc
.CreateElement(rdfprefix
+ ":RDF", NS
.RDF
);
60 foreach (string prefix
in ns
.GetPrefixes())
61 root
.SetAttribute("xmlns:" + prefix
, ns
.GetNamespace(prefix
));
62 doc
.AppendChild(root
);
65 public override NamespaceManager Namespaces { get { return ns; }
}
67 char[] normalizechars
= { '#', '/' }
;
69 private void Normalize(string uri
, out string prefix
, out string localname
) {
71 throw new InvalidOperationException("The empty URI cannot be used as an element node.");
73 if (ns
.Normalize(uri
, out prefix
, out localname
))
76 // No namespace prefix was registered, so come up with something.
78 int last
= uri
.LastIndexOfAny(normalizechars
);
80 throw new InvalidOperationException("No namespace was registered and no prefix could be automatically generated for <" + uri
+ ">");
82 int prev
= uri
.LastIndexOfAny(normalizechars
, last
-1);
84 throw new InvalidOperationException("No namespace was registered and no prefix could be automatically generated for <" + uri
+ ">");
86 string n
= uri
.Substring(0, last
+1);
87 localname
= uri
.Substring(last
+1);
89 // TODO: Make sure the local name (here and anywhere in this
90 // class) is a valid XML name.
92 if (Namespaces
.GetPrefix(n
) != null) {
93 prefix
= Namespaces
.GetPrefix(n
);
97 prefix
= uri
.Substring(prev
+1, last
-prev
-1);
99 // Remove all non-xmlable (letter) characters.
100 StringBuilder newprefix
= new StringBuilder();
101 foreach (char c
in prefix
)
102 if (char.IsLetter(c
))
104 prefix
= newprefix
.ToString();
106 if (prefix
.Length
== 0) {
107 // There were no letters in the prefix!
111 if (Namespaces
.GetNamespace(prefix
) == null) {
112 doc
.DocumentElement
.SetAttribute("xmlns:" + prefix
, n
);
113 Namespaces
.AddNamespace(n
, prefix
);
119 if (Namespaces
.GetNamespace(prefix
+ ctr
) == null) {
121 doc
.DocumentElement
.SetAttribute("xmlns:" + prefix
, n
);
122 Namespaces
.AddNamespace(n
, prefix
);
129 private void SetAttribute(XmlElement element
, string nsuri
, string prefix
, string localname
, string val
) {
130 XmlAttribute attr
= doc
.CreateAttribute(prefix
, localname
, nsuri
);
132 element
.SetAttributeNode(attr
);
135 private XmlElement
GetNode(string uri
, string type
, XmlElement context
) {
136 if (nodeMap
.ContainsKey(uri
))
137 return (XmlElement
)nodeMap
[uri
];
143 node
= doc
.CreateElement(ns
.GetPrefix(NS
.RDF
) + ":Description", NS
.RDF
);
145 string prefix
, localname
;
146 Normalize(type
, out prefix
, out localname
);
147 node
= doc
.CreateElement(prefix
+ ":" + localname
, ns
.GetNamespace(prefix
));
150 if (!anonAlloc
.ContainsKey(uri
)) {
151 SetAttribute(node
, NS
.RDF
, ns
.GetPrefix(NS
.RDF
), "about", uri
);
153 SetAttribute(node
, NS
.RDF
, ns
.GetPrefix(NS
.RDF
), "nodeID", uri
);
157 doc
.DocumentElement
.AppendChild(node
);
159 context
.AppendChild(node
);
165 private XmlElement
CreatePredicate(XmlElement subject
, string predicate
) {
166 string prefix
, localname
;
167 Normalize(predicate
, out prefix
, out localname
);
168 XmlElement pred
= doc
.CreateElement(prefix
+ ":" + localname
, ns
.GetNamespace(prefix
));
169 subject
.AppendChild(pred
);
173 public override void WriteStatement(string subj
, string pred
, string obj
) {
174 XmlElement subjnode
= GetNode(subj
, pred
== "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ? obj
: null, null);
175 if (pred
== "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") return;
177 XmlElement prednode
= CreatePredicate(subjnode
, pred
);
178 if (nodeMap
.ContainsKey(obj
)) {
179 if (!anonAlloc
.ContainsKey(obj
)) {
180 SetAttribute(prednode
, NS
.RDF
, ns
.GetPrefix(NS
.RDF
), "resource", obj
);
182 SetAttribute(prednode
, NS
.RDF
, ns
.GetPrefix(NS
.RDF
), "nodeID", obj
);
185 GetNode(obj
, null, prednode
);
189 public override void WriteStatement(string subj
, string pred
, Literal literal
) {
190 XmlElement subjnode
= GetNode(subj
, null, null);
191 XmlElement prednode
= CreatePredicate(subjnode
, pred
);
192 prednode
.InnerText
= literal
.Value
;
195 public override string CreateAnonymousEntity() {
196 string id
= "anon" + (anonCounter
++);
197 anonAlloc
[id
] = anonAlloc
;
201 public override void Close() {
209 internal class RdfXmlWriter2
: RdfWriter
{
212 NamespaceManager autons
;
214 long anonCounter
= 0;
215 string currentSubject
= null;
219 public RdfXmlWriter2(string file
) : this(file
, null) { }
221 public RdfXmlWriter2(string file
, NamespaceManager ns
) : this(GetWriter(file
), ns
) { }
223 public RdfXmlWriter2(TextWriter writer
) : this(writer
, null) { }
225 public RdfXmlWriter2(TextWriter writer
, NamespaceManager ns
) : this(NewWriter(writer
), ns
) { }
227 private static XmlWriter
NewWriter(TextWriter writer
) {
228 XmlTextWriter ret
= new XmlTextWriter(writer
);
229 ret
.Formatting
= Formatting
.Indented
;
231 ret
.IndentChar
= '\t';
235 public RdfXmlWriter2(XmlWriter writer
) : this(writer
, null) { }
237 public RdfXmlWriter2(XmlWriter writer
, NamespaceManager ns
) {
239 ns
= new NamespaceManager();
240 this.writer
= writer
;
242 //autons = new AutoPrefixNamespaceManager(this.ns);
245 public override NamespaceManager Namespaces { get { return ns; }
}
247 private bool Open(string resource
, string type
) {
248 bool emittedType
= false;
250 if (currentSubject
== null) {
251 rdf
= autons
.GetPrefix("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
252 writer
.WriteStartElement(rdf
+ ":RDF");
253 foreach (string prefix
in autons
.GetPrefixes())
254 writer
.WriteAttributeString("xmlns:" + prefix
, autons
.GetNamespace(prefix
));
256 if (currentSubject
!= null && currentSubject
!= resource
)
257 writer
.WriteEndElement();
258 if (currentSubject
== null || currentSubject
!= resource
) {
259 currentSubject
= resource
;
262 writer
.WriteStartElement(rdf
+ ":Description");
264 writer
.WriteStartElement(URI(type
));
268 writer
.WriteAttributeString(rdf
+ ":about", resource
);
274 public override void WriteStatement(string subj
, string pred
, string obj
) {
275 if (Open(subj
, pred
== "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ? obj
: null))
277 writer
.WriteStartElement(URI(pred
));
278 writer
.WriteAttributeString("rdf:resource", obj
);
279 writer
.WriteEndElement();
282 public override void WriteStatement(string subj
, string pred
, Literal literal
) {
284 writer
.WriteStartElement(URI(pred
));
285 // Should write language and datatype
286 writer
.WriteString(literal
.Value
);
287 writer
.WriteEndElement();
290 public override string CreateAnonymousEntity() {
291 return "_:anon" + (anonCounter
++);
294 public override void Close() {
296 if (currentSubject
!= null) {
297 writer
.WriteEndElement();
298 writer
.WriteEndElement();
304 private string URI(string uri
) {
305 if (uri
.StartsWith("_:anon")) return uri
;
306 string ret
= autons
.Normalize(uri
);
307 if (ret
.StartsWith("<"))
308 throw new InvalidOperationException("A namespace prefix must be defined for the URI " + ret
+ ".");