1414 * Created by Moritz Schubotz on 9/3/14.
1515 * Translated from http://git.wikimedia.org/blob/mediawiki%2Fextensions%2FMathSearch.git/31a80ae48d1aaa50da9103cea2e45a8dc2204b39/XQueryGenerator.php
1616 */
17- @ SuppressWarnings ("WeakerAccess" )
17+ @ SuppressWarnings ("WeakerAccess" )
1818public class XQueryGenerator {
19- private final Map <String , ArrayList <String >> qvar = new HashMap <>();
20- private String relativeXPath = "" ;
21- private String lengthConstraint = "" ;
22- private String header = "declare default element namespace \" http://www.w3.org/1998/Math/MathML\" ;\n " +
23- "for $m in db2-fn:xmlcolumn(\" math.math_mathml\" ) return\n " ;
24- private String footer = "data($m/*[1]/@alttext)" ;
25- public String getFooter () {
26- return footer ;
27- }
28-
29- public void setFooter (String footer ) {
30- this .footer = footer ;
31- }
32-
33- public String getHeader () {
34- return header ;
35- }
36-
37- public void setHeader (String header ) {
38- this .header = header ;
39- }
40-
41-
42- private final Document xml ;
43-
44- public XQueryGenerator (Document xml ) {
45- this .xml = xml ;
46- }
47-
48- private Node getMainElement () {
49- // Try to get main mws:expr first
50- NodeList expr = xml .getElementsByTagName ("mws:expr" );
51-
52- if (expr .getLength () > 0 ){
53- return new NdLst ( expr ).item (0 );
54- }
55- // if that fails try to get content MathML from an annotation tag
56- expr = xml .getElementsByTagName ("annotation-xml" );
57- for (Node node : new NdLst (expr )) {
58- if (node .hasAttributes () && node .getAttributes ().getNamedItem ("encoding" ).getNodeValue ().equals ("MathML-Content" )){
59- return node ;
60- }
61- }
62- // if that fails too interprete content of root MathML element as content MathML
63- expr = xml .getElementsByTagName ("math" );
64- if (expr .getLength () > 0 ){
65- return new NdLst ( expr ).item (0 );
66- }
67- return null ;
68- }
69-
70- public String toString () {
71- Node mainElement = getMainElement ();
72- if (mainElement == null )
73- return null ;
74- String fixedConstraints = generateConstraint (mainElement , true );
75- String qvarConstraintString = "" ;
76- for (Map .Entry <String , ArrayList <String >> entry : qvar .entrySet ()) {
77- String addString = "" ;
78- boolean newContent = false ;
79- if (entry .getValue ().size () > 1 ) {
80- String first = entry .getValue ().get (0 );
81- if (qvarConstraintString .length () > 0 ) {
82- addString += "\n and " ;
83- }
84- String lastSecond = "" ;
85- for (String second : entry .getValue ()) {
86- if (!second .equals (first )) {
87- if (lastSecond .length () > 0 ) {
88- addString += " and " ;
89- }
90- addString += "$x" + first + " = $x" + second ;
91- lastSecond = second ;
92- newContent = true ;
93- }
94- }
95- if (newContent ) {
96- qvarConstraintString += addString ;
97- }
98-
99- }
100-
101- }
102-
103-
104- return getHeader () + "for $x in $m//*:" +
105- (new NdLst (mainElement .getChildNodes ())).item (0 ).getLocalName () + "\n " +
106- fixedConstraints + "\n " +
107- "where" + "\n " +
108- lengthConstraint +
109- (((qvarConstraintString .length () > 0 ) && (lengthConstraint .length () > 0 )) ? " and " : "" ) +
110- qvarConstraintString + "\n " +
111- "return" + "\n " + getFooter ();
112-
113- }
114-
115- private String generateConstraint (Node node ) {
116- return generateConstraint (node , false );
117- }
118-
119- private String generateConstraint (Node node , boolean isRoot ) {
120- int i = 0 ;
121- String out = "" ;
122- boolean hasText = false ;
123- if (node == null ){
124- return null ;
125- }
126- NdLst nodeList = new NdLst (node .getChildNodes ());
127- for (Node child : nodeList ) {
128- if (child .getNodeName ().equals ("mws:qvar" )) {
129- i ++;
130- String qvarName = child .getTextContent ();
131- if (qvar .containsKey (qvarName )) {
132- qvar .get (qvarName ).add (relativeXPath + "/*[" + i + "]" );
133- } else {
134- qvar .put (qvarName , Lists .newArrayList (relativeXPath + "/*[" + i + "]" ));
135- }
136- } else {
137- if (child .getNodeType () == Node .ELEMENT_NODE ) {
138- i ++;
139- if (hasText ) {
140- out += " and " ;
141- }
142- if (!isRoot ) {
143- out += "*[" + i + "]/name() = '" + child .getLocalName () + "'" ;
144- }
145- hasText = true ;
146- if (child .hasChildNodes ()) {
147- if (!isRoot ) {
148- relativeXPath += "/*[" + i + "]" ;
149- out += " and *[" + i + "]" ;
150- }
151- out += "[" + generateConstraint (child ) + "]" ;
152- }
153-
154- } else if (child .getNodeType () == Node .TEXT_NODE ) {
155- out = "./text() = '" + child .getNodeValue () + "'" ;
156- }
157- }
158- }
159- if (!isRoot ) {
160- if (lengthConstraint .equals ("" )) {
161- lengthConstraint += "fn:count($x" + relativeXPath + "/*) = " + i + "\n " ;
162- } else {
163- lengthConstraint += " and fn:count($x" + relativeXPath + "/*) = " + i + "\n " ;
164- }
165- }
166- if (relativeXPath .length () > 0 ) {
167- relativeXPath = relativeXPath .substring (0 , relativeXPath .lastIndexOf ("/" ));
168- }
169- return out ;
170- }
19+ private final Map <String , ArrayList <String >> qvar = new HashMap <>();
20+ private String relativeXPath = "" ;
21+ private String lengthConstraint = "" ;
22+ private String header = "declare default element namespace \" http://www.w3.org/1998/Math/MathML\" ;\n " +
23+ "for $m in db2-fn:xmlcolumn(\" math.math_mathml\" ) return\n " ;
24+ private String footer = "data($m/*[1]/@alttext)" ;
25+
26+ public String getFooter () {
27+ return footer ;
28+ }
29+
30+ public void setFooter (String footer ) {
31+ this .footer = footer ;
32+ }
33+
34+ public String getHeader () {
35+ return header ;
36+ }
37+
38+ public void setHeader (String header ) {
39+ this .header = header ;
40+ }
41+
42+
43+ private final Document xml ;
44+
45+ public XQueryGenerator (Document xml ) {
46+ this .xml = xml ;
47+ }
48+
49+ private Node getMainElement () {
50+ return getMainElement ( xml );
51+ }
52+
53+ public static Node getMainElement (Document xml ) {
54+ // Try to get main mws:expr first
55+ NodeList expr = xml .getElementsByTagName ( "mws:expr" );
56+
57+ if ( expr .getLength () > 0 ) {
58+ return new NdLst ( expr ).item ( 0 );
59+ }
60+ // if that fails try to get content MathML from an annotation tag
61+ expr = xml .getElementsByTagName ( "annotation-xml" );
62+ for ( Node node : new NdLst ( expr ) ) {
63+ if ( node .hasAttributes () &&
64+ node .getAttributes ().getNamedItem ( "encoding" ).getNodeValue ().equals ( "MathML-Content" ) ) {
65+ return node ;
66+ }
67+ }
68+ // if that fails too interprete content of root MathML element as content MathML
69+ expr = xml .getElementsByTagName ( "math" );
70+ if ( expr .getLength () > 0 ) {
71+ return new NdLst ( expr ).item ( 0 );
72+ }
73+ return null ;
74+ }
75+
76+ public String toString () {
77+ Node mainElement = getMainElement ();
78+ if ( mainElement == null )
79+ return null ;
80+ String fixedConstraints = generateConstraint ( mainElement , true );
81+ String qvarConstraintString = "" ;
82+ for ( Map .Entry <String , ArrayList <String >> entry : qvar .entrySet () ) {
83+ String addString = "" ;
84+ boolean newContent = false ;
85+ if ( entry .getValue ().size () > 1 ) {
86+ String first = entry .getValue ().get ( 0 );
87+ if ( qvarConstraintString .length () > 0 ) {
88+ addString += "\n and " ;
89+ }
90+ String lastSecond = "" ;
91+ for ( String second : entry .getValue () ) {
92+ if ( !second .equals ( first ) ) {
93+ if ( lastSecond .length () > 0 ) {
94+ addString += " and " ;
95+ }
96+ addString += "$x" + first + " = $x" + second ;
97+ lastSecond = second ;
98+ newContent = true ;
99+ }
100+ }
101+ if ( newContent ) {
102+ qvarConstraintString += addString ;
103+ }
104+
105+ }
106+
107+ }
108+
109+
110+ return getHeader () + "for $x in $m//*:" +
111+ (new NdLst ( mainElement .getChildNodes () )).item ( 0 ).getLocalName () + "\n " +
112+ fixedConstraints + "\n " +
113+ "where" + "\n " +
114+ lengthConstraint +
115+ (((qvarConstraintString .length () > 0 ) && (lengthConstraint .length () > 0 )) ? " and " : "" ) +
116+ qvarConstraintString + "\n " +
117+ "return" + "\n " + getFooter ();
118+
119+ }
120+
121+ private String generateConstraint (Node node ) {
122+ return generateConstraint ( node , false );
123+ }
124+
125+ private String generateConstraint (Node node , boolean isRoot ) {
126+ int i = 0 ;
127+ String out = "" ;
128+ boolean hasText = false ;
129+ if ( node == null ) {
130+ return null ;
131+ }
132+ NdLst nodeList = new NdLst ( node .getChildNodes () );
133+ for ( Node child : nodeList ) {
134+ if ( child .getNodeName ().equals ( "mws:qvar" ) ) {
135+ i ++;
136+ String qvarName = child .getTextContent ();
137+ if ( qvar .containsKey ( qvarName ) ) {
138+ qvar .get ( qvarName ).add ( relativeXPath + "/*[" + i + "]" );
139+ } else {
140+ qvar .put ( qvarName , Lists .newArrayList ( relativeXPath + "/*[" + i + "]" ) );
141+ }
142+ } else {
143+ if ( child .getNodeType () == Node .ELEMENT_NODE ) {
144+ i ++;
145+ if ( hasText ) {
146+ out += " and " ;
147+ }
148+ if ( !isRoot ) {
149+ out += "*[" + i + "]/name() = '" + child .getLocalName () + "'" ;
150+ }
151+ hasText = true ;
152+ if ( child .hasChildNodes () ) {
153+ if ( !isRoot ) {
154+ relativeXPath += "/*[" + i + "]" ;
155+ out += " and *[" + i + "]" ;
156+ }
157+ out += "[" + generateConstraint ( child ) + "]" ;
158+ }
159+
160+ } else if ( child .getNodeType () == Node .TEXT_NODE ) {
161+ out = "./text() = '" + child .getNodeValue () + "'" ;
162+ }
163+ }
164+ }
165+ if ( !isRoot ) {
166+ if ( lengthConstraint .equals ( "" ) ) {
167+ lengthConstraint += "fn:count($x" + relativeXPath + "/*) = " + i + "\n " ;
168+ } else {
169+ lengthConstraint += " and fn:count($x" + relativeXPath + "/*) = " + i + "\n " ;
170+ }
171+ }
172+ if ( relativeXPath .length () > 0 ) {
173+ relativeXPath = relativeXPath .substring ( 0 , relativeXPath .lastIndexOf ( "/" ) );
174+ }
175+ return out ;
176+ }
171177
172178}
0 commit comments