1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * Copyright © 2017 Amdocs
\r
7 * * ===========================================================================
\r
8 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
9 * * you may not use this file except in compliance with the License.
\r
10 * * You may obtain a copy of the License at
\r
12 * * http://www.apache.org/licenses/LICENSE-2.0
\r
14 * * Unless required by applicable law or agreed to in writing, software
\r
15 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
16 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
17 * * See the License for the specific language governing permissions and
\r
18 * * limitations under the License.
\r
19 * * ============LICENSE_END====================================================
\r
21 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
23 ******************************************************************************/
\r
24 package com.att.rosetta;
\r
26 import java.io.IOException;
\r
27 import java.io.Writer;
\r
28 import java.util.ArrayList;
\r
29 import java.util.HashMap;
\r
30 import java.util.List;
\r
31 import java.util.Map;
\r
32 import java.util.Stack;
\r
34 import com.att.inno.env.util.IndentPrintWriter;
\r
35 import com.att.inno.env.util.StringBuilderWriter;
\r
37 public class OutXML extends Out{
\r
38 private static final String XMLNS_XSI = "xmlns:xsi";
\r
39 public static final String XML_INFO = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
\r
40 public static final String XML_SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance";
\r
42 private String root;
\r
43 private List<Prop> props;
\r
45 public OutXML(String root, String ... params) {
\r
47 props = new ArrayList<Prop>();
\r
48 for(String p : params) {
\r
49 String[] tv=p.split("=");
\r
51 props.add(new Prop(tv[0],tv[1]));
\r
55 public OutXML(JaxInfo jaxInfo) {
\r
56 this(jaxInfo.name,genNS(jaxInfo));
\r
59 public OutXML(InXML inXML) {
\r
60 this(inXML.jaxInfo.name,genNS(inXML.jaxInfo));
\r
63 private static String[] genNS(JaxInfo jaxInfo) {
\r
64 return new String[] {"xmlns=" + jaxInfo.ns};
\r
69 public<IN,S> void extract(IN in, Writer writer, Parse<IN,S> prs, boolean ... options) throws IOException, ParseException {
\r
70 Parsed<S> p = prs.newParsed();
\r
71 Stack<Level> stack = new Stack<Level>();
\r
72 // If it's an IndentPrintWriter, it is pretty printing.
\r
73 boolean pretty = (options.length>0&&options[0]);
\r
75 IndentPrintWriter ipw;
\r
77 if(writer instanceof IndentPrintWriter) {
\r
78 ipw = (IndentPrintWriter)writer;
\r
80 writer = ipw = new IndentPrintWriter(writer);
\r
85 boolean closeTag = false;
\r
86 Level level = new Level(null);
\r
87 while((p = prs.parse(in,p.reuse())).valid()) {
\r
88 if(!p.hasName() && level.multi!=null) {
\r
91 if(closeTag && p.event!=Parse.ATTRIB) {
\r
93 if(pretty)writer.append('\n');
\r
97 case Parse.START_DOC:
\r
98 if(!(options.length>1&&options[1])) // if not a fragment, print XML Info data
\r
99 if(pretty)ipw.println(XML_INFO);
\r
100 else writer.append(XML_INFO);
\r
102 case Parse.END_DOC:
\r
104 case Parse.START_OBJ:
\r
106 level = new Level(level);
\r
108 closeTag = tag(writer,level.sbw,pretty,pretty,p.name,null);
\r
109 } else if(root!=null && stack.size()==1) { // first Object
\r
110 closeTag = tag(writer,level.sbw,pretty,pretty,root,null);
\r
111 // Write Root Props
\r
112 for(Prop prop : props) {
\r
113 attrib(writer,pretty,prop.tag, prop.value,level);
\r
116 if(pretty)ipw.inc();
\r
118 case Parse.END_OBJ:
\r
120 closeTag = tag(writer,writer,pretty,false,p.name, XmlEscape.convert(p.sb));
\r
121 if(pretty)ipw.dec();
\r
122 writer.append(level.sbw.getBuffer());
\r
123 level = stack.pop();
\r
125 case Parse.START_ARRAY:
\r
126 level.multi = p.name;
\r
128 case Parse.END_ARRAY:
\r
130 closeTag = tag(writer,writer,pretty,false, p.name, XmlEscape.convert(p.sb));
\r
135 attrib(writer,pretty,p.name, XmlEscape.convert(p.sb), level);
\r
139 closeTag = tag(writer,writer,pretty, false,p.name, XmlEscape.convert(p.sb));
\r
143 writer.append(level.sbw.getBuffer());
\r
147 private class Level {
\r
148 public final StringBuilderWriter sbw;
\r
149 public String multi;
\r
150 private Level prev;
\r
151 private Map<String,String> nses;
\r
153 public Level(Level level) {
\r
154 sbw = new StringBuilderWriter();
\r
159 public boolean hasPrinted(String ns, String value, boolean create) {
\r
160 boolean rv = false;
\r
162 if(prev!=null)rv = prev.hasPrinted(ns, value, false);
\r
164 String v = nses.get(ns);
\r
165 return value.equals(v); // note: accomodates not finding NS as well
\r
168 if(create && !rv) {
\r
169 if(nses == null) nses = new HashMap<String,String>();
\r
170 nses.put(ns, value);
\r
179 private boolean tag(Writer fore, Writer aft, boolean pretty, boolean returns, String tag, String data) throws IOException {
\r
183 fore.append('>'); // if no data, it may need some attributes...
\r
185 if(returns)fore.append('\n');
\r
190 if(pretty)aft.append('\n');
\r
194 private void attrib(Writer fore, boolean pretty, String tag, String value, Level level) throws IOException {
\r
195 String realTag = tag.startsWith("__")?tag.substring(2):tag; // remove __
\r
196 if(realTag.equals(Parsed.EXTENSION_TAG)) { // Convert Derived name into XML defined Inheritance
\r
197 fore.append(" xsi:type=\"");
\r
198 fore.append(value);
\r
200 if(!level.hasPrinted(XMLNS_XSI, XML_SCHEMA_INSTANCE,true)) {
\r
202 fore.append(XMLNS_XSI);
\r
203 fore.append("=\"");
\r
204 fore.append(XML_SCHEMA_INSTANCE);
\r
208 if(realTag.startsWith("xmlns:") ) {
\r
209 if(level.hasPrinted(realTag, value, true)) {
\r
214 fore.append(realTag);
\r
215 fore.append("=\"");
\r
216 fore.append(value);
\r
222 public String logName() {
\r
223 return "Rosetta XML";
\r