├── .gitignore ├── LICENSE.txt ├── README.md ├── build.gradle ├── gradle.properties ├── gradle ├── publish.gradle ├── publish.gradle~ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── integration-test ├── java │ └── org │ │ └── xbib │ │ └── elasticsearch │ │ └── xml │ │ ├── MockNode.java │ │ ├── NodeTestUtils.java │ │ ├── XmlBuilderTest.java │ │ └── XmlPluginTest.java └── resources │ ├── dynamic-namespace.json │ ├── log4j2.xml │ ├── test.json │ └── xml-namespaces.properties └── main ├── java └── org │ └── xbib │ └── elasticsearch │ ├── common │ └── xcontent │ │ ├── XmlXContentBuilder.java │ │ ├── XmlXContentFactory.java │ │ ├── XmlXContentType.java │ │ └── xml │ │ ├── ISO9075.java │ │ ├── XML11Char.java │ │ ├── XMLChar.java │ │ ├── XmlNamespaceContext.java │ │ ├── XmlXContent.java │ │ ├── XmlXContentGenerator.java │ │ ├── XmlXContentParser.java │ │ └── XmlXParams.java │ ├── plugin │ └── xml │ │ └── XmlPlugin.java │ └── rest │ └── xml │ ├── XmlFilter.java │ └── XmlService.java ├── resources └── xml-namespaces.properties └── templates └── plugin-descriptor.properties /.gitignore: -------------------------------------------------------------------------------- 1 | /data 2 | /work 3 | /logs 4 | /.idea 5 | /target 6 | .DS_Store 7 | /.settings 8 | /.classpath 9 | /.project 10 | /.gradle 11 | /build -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch XML Plugin 2 | 3 | The XML plugin for Elasticsearch is a simple REST filter for sending and receiving XML. 4 | 5 | It converts REST HTTP bodies from JSON to XML. It is hoped to be useful to embed Elasticsearch in XML environments. 6 | 7 | For sending XML, you must add a HTTP header `Content-type: application/xml` 8 | 9 | For receiving XML, you must add a HTTP header `Accept: application/xml` 10 | 11 | Each JSON name is converted to a valid XML element name according to ISO 9075. 12 | 13 | Because XML is more restrictive than JSON, do not assume that XML can server as a full replacement for JSON in Elasticsearch. 14 | 15 | The JSON to XML conversion uses some tricks. Therefore you must not be surprised by edge cases where XML give peculiar results. 16 | 17 | ## Versions 18 | 19 | | Elasticsearch version | Plugin | Release date | 20 | | ------------------------ | -----------| -------------| 21 | | 2.3.5 | 2.3.5.1 | Aug 24, 2016 | 22 | | 2.3.5 | 2.3.5.0 | Aug 13, 2016 | 23 | | 1.6.0 | 1.6.0.2 | Jul 3, 2015 | 24 | | 1.4.2 | 1.4.2.0 | Feb 2, 2015 | 25 | | 1.3.2 | 1.3.0.0 | Aug 19, 2014 | 26 | | 1.2.2 | 1.2.2.1 | Jul 22, 2014 | 27 | 28 | ## Installation 29 | 30 | ### Elasticsearch 2.x 31 | 32 | ./bin/plugin install 'http://xbib.org/repository/org/xbib/elasticsearch/plugin/elasticsearch-xml/2.3.5.1/elasticsearch-xml-2.3.5.1-plugin.zip' 33 | 34 | ### Elasticsearch 1.x 35 | 36 | ./bin/plugin --install xml --url http://xbib.org/repository/org/xbib/elasticsearch/plugin/elasticsearch-xml/1.6.0.2/elasticsearch-xml-1.6.0.2-plugin.zip 37 | 38 | Do not forget to restart the node after installing. 39 | 40 | ## Project docs 41 | 42 | The Maven project site is available at [Github](http://jprante.github.io/elasticsearch-xml) 43 | 44 | 45 | # Examples 46 | 47 | Consider the following JSON documents. 48 | 49 | Command: 50 | 51 | curl '0:9200/_search?pretty' 52 | 53 | Output: 54 | 55 | { 56 | "took" : 2, 57 | "timed_out" : false, 58 | "_shards" : { 59 | "total" : 5, 60 | "successful" : 5, 61 | "failed" : 0 62 | }, 63 | "hits" : { 64 | "total" : 7, 65 | "max_score" : 1.0, 66 | "hits" : [ { 67 | "_index" : "a", 68 | "_type" : "b", 69 | "_id" : "3", 70 | "_score" : 1.0, "_source" : {"name":"Jörg"} 71 | }, { 72 | "_index" : "a", 73 | "_type" : "b", 74 | "_id" : "2", 75 | "_score" : 1.0, "_source" : {"es:foo":"bar"} 76 | }, { 77 | "_index" : "a", 78 | "_type" : "b", 79 | "_id" : "7", 80 | "_score" : 1.0, "_source" : {"":"Hello World"} 81 | }, { 82 | "_index" : "a", 83 | "_type" : "b", 84 | "_id" : "c", 85 | "_score" : 1.0, "_source" : {"Hello":"World"} 86 | }, { 87 | "_index" : "a", 88 | "_type" : "b", 89 | "_id" : "6", 90 | "_score" : 1.0, "_source" : {"@context":{"p":"http://another.org"},"p:foo":"bar"} 91 | }, { 92 | "_index" : "a", 93 | "_type" : "b", 94 | "_id" : "4", 95 | "_score" : 1.0, "_source" : {"@context":{"p":"http://example.org"},"p:foo":"bar"} 96 | }, { 97 | "_index" : "a", 98 | "_type" : "b", 99 | "_id" : "5", 100 | "_score" : 1.0, "_source" : {"@context":{"p":"http://dummy.org"},"p:foo":"bar"} 101 | } ] 102 | } 103 | } 104 | 105 | The same in XML. 106 | 107 | Command: 108 | 109 | curl -H 'Accept: application/xml' '0:9200/_search?pretty' 110 | 111 | Output: 112 | 113 | 114 | 3 115 | false 116 | 117 | 5 118 | 5 119 | 0 120 | 121 | 122 | 7 123 | 1.0 124 | 125 | a 126 | b 127 | 3 128 | 1.0 129 | 130 | Jörg 131 | 132 | 133 | 134 | a 135 | b 136 | 2 137 | 1.0 138 | 139 | bar 140 | 141 | 142 | 143 | a 144 | b 145 | 7 146 | 1.0 147 | 148 | <>Hello World 149 | 150 | 151 | 152 | a 153 | b 154 | c 155 | 1.0 156 | 157 | World 158 | 159 | 160 | 161 | a 162 | b 163 | 6 164 | 1.0 165 | 166 | 167 | bar 168 | 169 | 170 | 171 | a 172 | b 173 | 4 174 | 1.0 175 | 176 | 177 | bar 178 | 179 | 180 | 181 | a 182 | b 183 | 5 184 | 1.0 185 | 186 | 187 | bar 188 | 189 | 190 | 191 | 192 | As shown above, with the `@context` name in JSON, you can declare XML namespaces. 193 | 194 | The `@context` is similar to JSON-LD's `@context` but not that powerful. 195 | 196 | ## XML Attributes 197 | 198 | If JSON names are used with a `@` as starting letter, they will appear as XML attribute. 199 | 200 | If XML attributes are passed in sending documents, they will appear as normal JSON names. 201 | 202 | If nested XML do not lead to a proper JSON object, an empty JSON name is used, which might not be useful. 203 | 204 | Command: 205 | 206 | curl -XPOST -H 'Accept: application/xml' '0:9200/a/c/1' -d 'value' 207 | curl '0:9200/a/c/1?pretty' 208 | 209 | Output: 210 | 211 | { 212 | "_index" : "a", 213 | "_type" : "c", 214 | "_id" : "1", 215 | "_version" : 1, 216 | "found" : true, "_source" : {"name":{"attr":"test","":"value"}} 217 | } 218 | 219 | Another example. 220 | 221 | Command: 222 | 223 | curl -XPOST '0:9200/a/c/2' -d '{"test":{"@attr": "value"}}' 224 | curl -H 'Accept: application/xml' '0:9200/a/c/2?pretty' 225 | 226 | Output: 227 | 228 | 229 | a 230 | c 231 | 2 232 | 1 233 | true 234 | 235 | 236 | 237 | 238 | 239 | 240 | # License 241 | 242 | Elasticsearch XML Plugin 243 | 244 | Copyright (C) 2014 Jörg Prante 245 | 246 | Licensed under the Apache License, Version 2.0 (the "License"); 247 | you may not use this file except in compliance with the License. 248 | You may obtain a copy of the License at 249 | 250 | http://www.apache.org/licenses/LICENSE-2.0 251 | 252 | Unless required by applicable law or agreed to in writing, software 253 | distributed under the License is distributed on an "AS IS" BASIS, 254 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 255 | See the License for the specific language governing permissions and 256 | limitations under the License. 257 | 258 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | 2 | println "Host: " + java.net.InetAddress.getLocalHost() 3 | println "Gradle: " + gradle.gradleVersion + " JVM: " + org.gradle.internal.jvm.Jvm.current() + " Groovy: " + GroovySystem.getVersion() 4 | println "Build: group: '${project.group}', name: '${project.name}', version: '${project.version}'" 5 | 6 | ext { 7 | pluginName = 'xml' 8 | pluginClassname = 'org.xbib.elasticsearch.plugin.xml.XmlPlugin' 9 | pluginDescription = 'XML plugin for Elasticsearch' 10 | user = 'jprante' 11 | name = 'elasticsearch-xml' 12 | scmUrl = 'https://github.com/' + user + '/' + name 13 | scmConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' 14 | scmDeveloperConnection = 'scm:git:git://github.com/' + user + '/' + name + '.git' 15 | versions = [ 16 | 'elasticsearch' : '2.3.5', 17 | 'jackson': '2.6.6', 18 | 'woodstox' : '5.0.2', 19 | 'stax2-api': '4.0.0', 20 | 'log4j': '2.5', 21 | 'junit' : '4.12' 22 | ] 23 | } 24 | 25 | buildscript { 26 | repositories { 27 | mavenLocal() 28 | mavenCentral() 29 | jcenter() 30 | maven { 31 | url "http://xbib.org/repository" 32 | } 33 | } 34 | dependencies { 35 | classpath 'org.ajoberstar:gradle-git:1.4.2' 36 | classpath 'co.riiid:gradle-github-plugin:0.4.2' 37 | } 38 | } 39 | 40 | apply plugin: 'java' 41 | apply plugin: 'maven' 42 | apply plugin: 'signing' 43 | 44 | repositories { 45 | mavenLocal() 46 | mavenCentral() 47 | jcenter() 48 | maven { 49 | url "http://xbib.org/repository" 50 | } 51 | } 52 | 53 | sourceSets { 54 | integrationTest { 55 | java { 56 | compileClasspath += main.output + test.output 57 | runtimeClasspath += main.output + test.output 58 | srcDir file('src/integration-test/java') 59 | } 60 | resources.srcDir file('src/integration-test/resources') 61 | } 62 | } 63 | 64 | sourceCompatibility = 1.7 65 | targetCompatibility = 1.7 66 | 67 | configurations { 68 | wagon 69 | integrationTestCompile.extendsFrom testCompile 70 | integrationTestRuntime.extendsFrom testRuntime 71 | releaseJars { 72 | extendsFrom runtime 73 | exclude group: 'org.elasticsearch' 74 | exclude module: 'jna' 75 | exclude module: 'jackson-core' 76 | exclude module: 'jackson-dataformat-smile' 77 | exclude module: 'jackson-dataformat-yaml' 78 | } 79 | } 80 | 81 | dependencies { 82 | compile "org.elasticsearch:elasticsearch:${versions.elasticsearch}" 83 | compile "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${versions.jackson}" 84 | compile "com.fasterxml.woodstox:woodstox-core:${versions.woodstox}" 85 | compile "org.codehaus.woodstox:stax2-api:${versions.'stax2-api'}" 86 | testCompile "junit:junit:${versions.junit}" 87 | testCompile "org.apache.logging.log4j:log4j-slf4j-impl:${versions.log4j}" 88 | testCompile "org.apache.logging.log4j:log4j-core:${versions.log4j}" 89 | releaseJars "${project.group}:${project.name}:${project.version}" 90 | wagon 'org.apache.maven.wagon:wagon-ssh-external:2.10' 91 | } 92 | 93 | 94 | tasks.withType(JavaCompile) { 95 | options.compilerArgs << "-Xlint:unchecked,deprecation" 96 | } 97 | 98 | task makePluginDescriptor(type: Copy) { 99 | from 'src/main/templates' 100 | into 'build/tmp/plugin' 101 | expand([ 102 | 'descriptor': [ 103 | 'name': pluginName, 104 | 'classname': pluginClassname, 105 | 'description': pluginDescription, 106 | 'jvm': true, 107 | 'site': false, 108 | 'isolated': true, 109 | 'version': project.property('version'), 110 | 'javaVersion': project.property('targetCompatibility'), 111 | 'elasticsearchVersion' : versions.elasticsearch 112 | ] 113 | ]) 114 | } 115 | 116 | task buildPluginZip(type: Zip, dependsOn: [':jar', ':makePluginDescriptor']) { 117 | from configurations.releaseJars 118 | from 'build/tmp/plugin' 119 | classifier = 'plugin' 120 | } 121 | 122 | task unpackPlugin(type: Copy, dependsOn: [':buildPluginZip']) { 123 | delete "plugins" 124 | from configurations.releaseJars 125 | from 'build/tmp/plugin' 126 | into "plugins/${pluginName}" 127 | } 128 | 129 | task integrationTest(type: Test, dependsOn: ['unpackPlugin']) { 130 | testClassesDir = sourceSets.integrationTest.output.classesDir 131 | classpath = configurations.integrationTestCompile 132 | classpath += fileTree("plugins/${pluginName}").include('*.jar') 133 | classpath += sourceSets.integrationTest.output 134 | // without this trick to remove identical jars from classpath, an Elasticsearch bug whines about a "jar hell" 135 | classpath -= configurations.releaseJars 136 | outputs.upToDateWhen { false } 137 | systemProperty 'path.home', projectDir.absolutePath 138 | testLogging.showStandardStreams = false 139 | } 140 | 141 | integrationTest.mustRunAfter test 142 | check.dependsOn integrationTest 143 | 144 | clean { 145 | delete "plugins" 146 | delete "logs" 147 | } 148 | 149 | task javadocJar(type: Jar, dependsOn: classes) { 150 | from javadoc 151 | into "build/tmp" 152 | classifier 'javadoc' 153 | } 154 | 155 | task sourcesJar(type: Jar, dependsOn: classes) { 156 | from sourceSets.main.allSource 157 | into "build/tmp" 158 | classifier 'sources' 159 | } 160 | 161 | artifacts { 162 | archives javadocJar, sourcesJar, buildPluginZip 163 | } 164 | 165 | if (project.hasProperty('signing.keyId')) { 166 | signing { 167 | sign configurations.archives 168 | } 169 | } 170 | 171 | apply from: 'gradle/publish.gradle' 172 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group = org.xbib.elasticsearch.plugin 2 | version = 2.3.5.1 3 | org.gradle.daemon = true -------------------------------------------------------------------------------- /gradle/publish.gradle: -------------------------------------------------------------------------------- 1 | 2 | task xbibUpload(type: Upload) { 3 | configuration = configurations.archives 4 | uploadDescriptor = true 5 | repositories { 6 | if (project.hasProperty("xbibUsername")) { 7 | mavenDeployer { 8 | configuration = configurations.wagon 9 | repository(url: uri('scpexe://xbib.org/repository')) { 10 | authentication(userName: xbibUsername, privateKey: xbibPrivateKey) 11 | } 12 | } 13 | } 14 | } 15 | } 16 | 17 | task sonaTypeUpload(type: Upload) { 18 | configuration = configurations.archives 19 | uploadDescriptor = true 20 | repositories { 21 | if (project.hasProperty('ossrhUsername')) { 22 | mavenDeployer { 23 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 24 | repository(url: uri(ossrhReleaseUrl)) { 25 | authentication(userName: ossrhUsername, password: ossrhPassword) 26 | } 27 | snapshotRepository(url: uri(ossrhSnapshotUrl)) { 28 | authentication(userName: ossrhUsername, password: ossrhPassword) 29 | } 30 | pom.project { 31 | name pluginName 32 | description pluginDescription 33 | packaging 'jar' 34 | inceptionYear '2012' 35 | url scmUrl 36 | organization { 37 | name 'xbib' 38 | url 'http://xbib.org' 39 | } 40 | developers { 41 | developer { 42 | id user 43 | name 'Jörg Prante' 44 | email 'joergprante@gmail.com' 45 | url 'https://github.com/jprante' 46 | } 47 | } 48 | scm { 49 | url scmUrl 50 | connection scmConnection 51 | developerConnection scmDeveloperConnection 52 | } 53 | licenses { 54 | license { 55 | name 'The Apache License, Version 2.0' 56 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /gradle/publish.gradle~: -------------------------------------------------------------------------------- 1 | 2 | task xbibUpload(type: Upload) { 3 | configuration = configurations.archives 4 | uploadDescriptor = true 5 | repositories { 6 | if (project.hasProperty("xbibUsername")) { 7 | mavenDeployer { 8 | configuration = configurations.wagon 9 | repository(url: uri('scpexe://xbib.org/repository')) { 10 | authentication(userName: xbibUsername, privateKey: xbibPrivateKey) 11 | } 12 | } 13 | } 14 | } 15 | } 16 | 17 | task sonaTypeUpload(type: Upload) { 18 | configuration = configurations.archives 19 | uploadDescriptor = true 20 | repositories { 21 | if (project.hasProperty('ossrhUsername')) { 22 | mavenDeployer { 23 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 24 | repository(url: uri(ossrhReleaseUrl)) { 25 | authentication(userName: ossrhUsername, password: ossrhPassword) 26 | } 27 | snapshotRepository(url: uri(ossrhSnapshotUrl)) { 28 | authentication(userName: ossrhUsername, password: ossrhPassword) 29 | } 30 | pom.project { 31 | name pluginName 32 | description pluginDescription 33 | packaging 'jar' 34 | inceptionYear '2012' 35 | url scmUrl 36 | organization { 37 | name 'xbib' 38 | url 'http://xbib.org' 39 | } 40 | developers { 41 | developer { 42 | id user 43 | name 'Jörg Prante' 44 | email 'joergprante@gmail.com' 45 | url 'https://github.com/jprante' 46 | } 47 | } 48 | scm { 49 | url scmUrl 50 | connection scmConnection 51 | developerConnection scmDeveloperConnection 52 | } 53 | licenses { 54 | license { 55 | name 'The Apache License, Version 2.0' 56 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 57 | } 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | 65 | if (project.hasProperty('githubToken')) { 66 | github { 67 | owner = user 68 | token = githubToken 69 | repo = project.name 70 | name = project.version 71 | tagName = project.version 72 | targetCommitish = 'master' 73 | assets = [ 74 | "build/distributions/${project.name}-${project.version}-plugin.zip" 75 | ] 76 | } 77 | githubRelease { 78 | dependsOn gitRelease, buildPluginZip 79 | } 80 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jprante/elasticsearch-xml/5e74ec61ba52a4616f6cc2b5c8ff60c8e150cee1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Aug 24 19:26:48 CEST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 165 | if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then 166 | cd "$(dirname "$0")" 167 | fi 168 | 169 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 170 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'elasticsearch-xml' -------------------------------------------------------------------------------- /src/integration-test/java/org/xbib/elasticsearch/xml/MockNode.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xbib.elasticsearch.xml; 3 | 4 | import org.elasticsearch.Version; 5 | import org.elasticsearch.common.settings.Settings; 6 | import org.elasticsearch.node.Node; 7 | import org.elasticsearch.node.internal.InternalSettingsPreparer; 8 | import org.elasticsearch.plugins.Plugin; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | 13 | public class MockNode extends Node { 14 | 15 | public MockNode(Settings settings, Collection> classpathPlugins) { 16 | super(InternalSettingsPreparer.prepareEnvironment(settings, null), Version.CURRENT, classpathPlugins); 17 | } 18 | 19 | public MockNode(Settings settings, Class classpathPlugin) { 20 | this(settings, list(classpathPlugin)); 21 | } 22 | 23 | private static Collection> list(Class classpathPlugin) { 24 | Collection> list = new ArrayList<>(); 25 | list.add(classpathPlugin); 26 | return list; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/integration-test/java/org/xbib/elasticsearch/xml/NodeTestUtils.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.xml; 2 | 3 | import org.elasticsearch.ElasticsearchTimeoutException; 4 | import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction; 5 | import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest; 6 | import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; 7 | import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest; 8 | import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; 9 | import org.elasticsearch.client.support.AbstractClient; 10 | import org.elasticsearch.cluster.health.ClusterHealthStatus; 11 | import org.elasticsearch.common.logging.ESLogger; 12 | import org.elasticsearch.common.logging.ESLoggerFactory; 13 | import org.elasticsearch.common.settings.Settings; 14 | import org.elasticsearch.common.transport.InetSocketTransportAddress; 15 | import org.elasticsearch.common.unit.TimeValue; 16 | import org.elasticsearch.node.Node; 17 | import org.junit.After; 18 | import org.junit.Before; 19 | import org.xbib.elasticsearch.plugin.xml.XmlPlugin; 20 | 21 | import java.io.IOException; 22 | import java.nio.file.FileVisitResult; 23 | import java.nio.file.Files; 24 | import java.nio.file.Path; 25 | import java.nio.file.Paths; 26 | import java.nio.file.SimpleFileVisitor; 27 | import java.nio.file.attribute.BasicFileAttributes; 28 | import java.util.HashMap; 29 | import java.util.Map; 30 | import java.util.concurrent.atomic.AtomicInteger; 31 | 32 | import static org.elasticsearch.common.settings.Settings.settingsBuilder; 33 | 34 | public class NodeTestUtils { 35 | 36 | private final static ESLogger logger = ESLoggerFactory.getLogger("test"); 37 | 38 | private Map nodes = new HashMap<>(); 39 | 40 | private Map clients = new HashMap<>(); 41 | 42 | private AtomicInteger counter = new AtomicInteger(); 43 | 44 | private String cluster; 45 | 46 | private String host; 47 | 48 | private int port; 49 | 50 | @Before 51 | public void startNodes() { 52 | try { 53 | logger.info("starting"); 54 | setClusterName(); 55 | startNode("1"); 56 | findNodeAddress(); 57 | try { 58 | ClusterHealthResponse healthResponse = client("1").execute(ClusterHealthAction.INSTANCE, 59 | new ClusterHealthRequest().waitForStatus(ClusterHealthStatus.GREEN).timeout(TimeValue.timeValueSeconds(30))).actionGet(); 60 | if (healthResponse != null && healthResponse.isTimedOut()) { 61 | throw new IOException("cluster state is " + healthResponse.getStatus().name() 62 | + ", from here on, everything will fail!"); 63 | } 64 | } catch (ElasticsearchTimeoutException e) { 65 | throw new IOException("timeout, cluster does not respond to health request, cowardly refusing to continue with operations"); 66 | } 67 | } catch (Throwable t) { 68 | logger.error("startNodes failed", t); 69 | } 70 | } 71 | 72 | @After 73 | public void stopNodes() { 74 | try { 75 | closeNodes(); 76 | } catch (Exception e) { 77 | logger.error("can not close nodes", e); 78 | } finally { 79 | try { 80 | deleteFiles(); 81 | logger.info("data files wiped"); 82 | Thread.sleep(2000L); 83 | } catch (IOException e) { 84 | logger.error(e.getMessage(), e); 85 | } catch (InterruptedException e) { 86 | // ignore 87 | } 88 | } 89 | } 90 | 91 | protected void setClusterName() { 92 | this.cluster = "test-functionscore-conditionalboost-" 93 | + "-" + System.getProperty("user.name") 94 | + "-" + counter.incrementAndGet(); 95 | } 96 | 97 | protected String getClusterName() { 98 | return cluster; 99 | } 100 | 101 | protected Settings getSettings() { 102 | return settingsBuilder() 103 | .put("host", host) 104 | .put("port", port) 105 | .put("cluster.name", cluster) 106 | .put("path.home", getHome()) 107 | .build(); 108 | } 109 | 110 | protected Settings getNodeSettings() { 111 | return settingsBuilder() 112 | .put("cluster.name", cluster) 113 | .put("cluster.routing.schedule", "50ms") 114 | .put("cluster.routing.allocation.disk.threshold_enabled", false) 115 | .put("discovery.zen.multicast.enabled", true) 116 | .put("discovery.zen.multicast.ping_timeout", "5s") 117 | .put("http.enabled", true) 118 | .put("threadpool.bulk.size", Runtime.getRuntime().availableProcessors()) 119 | .put("threadpool.bulk.queue_size", 16 * Runtime.getRuntime().availableProcessors()) // default is 50, too low 120 | .put("index.number_of_replicas", 0) 121 | .put("path.home", getHome()) 122 | .build(); 123 | } 124 | 125 | protected String getHome() { 126 | return System.getProperty("path.home"); 127 | } 128 | 129 | public void startNode(String id) throws IOException { 130 | buildNode(id).start(); 131 | } 132 | 133 | public AbstractClient client(String id) { 134 | return clients.get(id); 135 | } 136 | 137 | private void closeNodes() throws IOException { 138 | logger.info("closing all clients"); 139 | for (AbstractClient client : clients.values()) { 140 | client.close(); 141 | } 142 | clients.clear(); 143 | logger.info("closing all nodes"); 144 | for (Node node : nodes.values()) { 145 | if (node != null) { 146 | node.close(); 147 | } 148 | } 149 | nodes.clear(); 150 | logger.info("all nodes closed"); 151 | } 152 | 153 | protected void findNodeAddress() { 154 | NodesInfoRequest nodesInfoRequest = new NodesInfoRequest().transport(true); 155 | NodesInfoResponse response = client("1").admin().cluster().nodesInfo(nodesInfoRequest).actionGet(); 156 | Object obj = response.iterator().next().getTransport().getAddress() 157 | .publishAddress(); 158 | if (obj instanceof InetSocketTransportAddress) { 159 | InetSocketTransportAddress address = (InetSocketTransportAddress) obj; 160 | host = address.address().getHostName(); 161 | port = address.address().getPort(); 162 | } 163 | } 164 | 165 | private Node buildNode(String id) throws IOException { 166 | Settings nodeSettings = settingsBuilder() 167 | .put(getNodeSettings()) 168 | .put("name", id) 169 | .build(); 170 | logger.info("settings={}", nodeSettings.getAsMap()); 171 | // ES 2.1 renders NodeBuilder as useless 172 | Node node = new MockNode(nodeSettings, XmlPlugin.class); 173 | AbstractClient client = (AbstractClient)node.client(); 174 | nodes.put(id, node); 175 | clients.put(id, client); 176 | logger.info("clients={}", clients); 177 | return node; 178 | } 179 | 180 | private static void deleteFiles() throws IOException { 181 | Path directory = Paths.get(System.getProperty("path.home") + "/data"); 182 | Files.walkFileTree(directory, new SimpleFileVisitor() { 183 | @Override 184 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { 185 | Files.delete(file); 186 | return FileVisitResult.CONTINUE; 187 | } 188 | 189 | @Override 190 | public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { 191 | Files.delete(dir); 192 | return FileVisitResult.CONTINUE; 193 | } 194 | 195 | }); 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /src/integration-test/java/org/xbib/elasticsearch/xml/XmlBuilderTest.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.xml; 2 | 3 | import org.elasticsearch.common.io.Streams; 4 | import org.elasticsearch.common.xcontent.XContentParser; 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | import org.xbib.elasticsearch.common.xcontent.XmlXContentBuilder; 8 | import org.xbib.elasticsearch.common.xcontent.XmlXContentFactory; 9 | import org.xbib.elasticsearch.common.xcontent.XmlXContentType; 10 | import org.xbib.elasticsearch.common.xcontent.xml.XmlNamespaceContext; 11 | import org.xbib.elasticsearch.common.xcontent.xml.XmlXParams; 12 | 13 | import javax.xml.namespace.QName; 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | 18 | import static org.xbib.elasticsearch.common.xcontent.XmlXContentFactory.xmlBuilder; 19 | 20 | public class XmlBuilderTest extends Assert { 21 | 22 | @Test 23 | public void testXml() throws Exception { 24 | XmlXContentBuilder builder = xmlBuilder(); 25 | builder.startObject().field("Hello", "World").endObject(); 26 | assertEquals( 27 | "World", 28 | builder.string() 29 | ); 30 | } 31 | 32 | @Test 33 | public void testXmlParams() throws Exception { 34 | XmlXParams params = new XmlXParams(); 35 | XmlXContentBuilder builder = xmlBuilder(params); 36 | builder.startObject().field("Hello", "World").endObject(); 37 | assertEquals( 38 | "World", 39 | builder.string() 40 | 41 | ); 42 | } 43 | 44 | @Test 45 | public void testXmlNamespaces() throws Exception { 46 | XmlNamespaceContext context = XmlNamespaceContext.getDefaultInstance(); 47 | XmlXParams params = new XmlXParams(context); 48 | XmlXContentBuilder builder = xmlBuilder(params); 49 | builder.startObject() 50 | .field("dc:creator", "John Doe") 51 | .endObject(); 52 | assertEquals( 53 | "John Doe", 58 | builder.string() 59 | ); 60 | } 61 | 62 | @Test 63 | public void testXmlCustomNamespaces() throws Exception { 64 | QName root = new QName("http://elasticsearch.org/ns/1.0/", "result", ""); 65 | XmlNamespaceContext context = XmlNamespaceContext.getDefaultInstance(); 66 | context.addNamespace("abc", "http://localhost"); 67 | XmlXParams params = new XmlXParams(root, context); 68 | XmlXContentBuilder builder = xmlBuilder(params); 69 | builder.startObject() 70 | .field("abc:creator", "John Doe") 71 | .endObject(); 72 | System.err.println(builder.string()); 73 | assertEquals( 74 | "John Doe", 80 | builder.string() 81 | ); 82 | } 83 | 84 | @Test 85 | public void testXmlObject() throws Exception { 86 | XmlXParams params = new XmlXParams(); 87 | XmlXContentBuilder builder = xmlBuilder(params); 88 | builder.startObject() 89 | .startObject("author") 90 | .field("creator", "John Doe") 91 | .field("role", "writer") 92 | .endObject() 93 | .startObject("author") 94 | .field("creator", "Joe Smith") 95 | .field("role", "illustrator") 96 | .endObject() 97 | .endObject(); 98 | assertEquals( 99 | "John DoewriterJoe Smithillustrator", 100 | builder.string()); 101 | } 102 | 103 | @Test 104 | public void testXmlAttributes() throws Exception { 105 | XmlNamespaceContext namespaceContext = XmlNamespaceContext.newInstance(); 106 | namespaceContext.addNamespace("es", "http://elasticsearch.org/ns/1.0/"); 107 | XmlXParams params = new XmlXParams(namespaceContext); 108 | XmlXContentBuilder builder = xmlBuilder(params); 109 | builder.startObject() 110 | .startObject("author") 111 | .field("@name", "John Doe") 112 | .field("@id", 1) 113 | .endObject() 114 | .endObject(); 115 | assertEquals( 116 | "", 117 | builder.string()); 118 | } 119 | 120 | @Test 121 | public void testXmlArrayOfValues() throws Exception { 122 | XmlXParams params = new XmlXParams(); 123 | XmlXContentBuilder builder = xmlBuilder(params); 124 | builder.startObject() 125 | .array("author", "John Doe", "Joe Smith") 126 | .endObject(); 127 | assertEquals( 128 | "John DoeJoe Smith", 129 | builder.string() 130 | ); 131 | } 132 | 133 | @Test 134 | public void testXmlArrayOfObjects() throws Exception { 135 | XmlXParams params = new XmlXParams(); 136 | XmlXContentBuilder builder = xmlBuilder(params); 137 | builder.startObject() 138 | .startArray("author") 139 | .startObject() 140 | .field("creator", "John Doe") 141 | .field("role", "writer") 142 | .endObject() 143 | .startObject() 144 | .field("creator", "Joe Smith") 145 | .field("role", "illustrator") 146 | .endObject() 147 | .endArray() 148 | .endObject(); 149 | assertEquals( 150 | "John DoewriterJoe Smithillustrator", 151 | builder.string() 152 | ); 153 | } 154 | 155 | @Test 156 | public void testParseJson() throws Exception { 157 | XmlNamespaceContext context = XmlNamespaceContext.getDefaultInstance(); 158 | context.addNamespace("bib","info:srw/cql-context-set/1/bib-v1/"); 159 | context.addNamespace("abc", "http://localhost/"); 160 | context.addNamespace("xbib", "http://xbib.org/"); 161 | context.addNamespace("lia", "http://xbib.org/namespaces/lia/"); 162 | XmlXParams params = new XmlXParams(context); 163 | InputStream in = getClass().getResourceAsStream("/test.json"); 164 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 165 | Streams.copy(in, out); 166 | byte[] buf = out.toByteArray(); 167 | String s = convertToXml(params, buf, 0, buf.length, false); 168 | assertEquals(53194, s.length()); 169 | } 170 | 171 | @Test 172 | public void testDynamicNamespaces() throws Exception { 173 | XmlNamespaceContext context = XmlNamespaceContext.getDefaultInstance(); 174 | XmlXParams params = new XmlXParams(context); 175 | InputStream in = getClass().getResourceAsStream("/dynamic-namespace.json"); 176 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 177 | Streams.copy(in, out); 178 | byte[] buf = out.toByteArray(); 179 | String s = convertToXml(params, buf, 0, buf.length, false); 180 | assertEquals( 181 | "bar", 182 | s 183 | ); 184 | } 185 | 186 | public static String convertToXml(XmlXParams params, byte[] data, int offset, int length) throws IOException { 187 | return convertToXml(params, data, offset, length, false); 188 | } 189 | 190 | public static String convertToXml(XmlXParams params, byte[] data, int offset, int length, boolean prettyPrint) throws IOException { 191 | XmlXContentType xmlXContentType = XmlXContentFactory.xContentType(data, offset, length); 192 | XContentParser parser = null; 193 | try { 194 | parser = XmlXContentFactory.xContent(xmlXContentType).createParser(data, offset, length); 195 | parser.nextToken(); 196 | XmlXContentBuilder builder = XmlXContentFactory.xmlBuilder(params); 197 | if (prettyPrint) { 198 | builder.prettyPrint(); 199 | } 200 | builder.copyCurrentStructure(parser); 201 | return builder.string(); 202 | } finally { 203 | if (parser != null) { 204 | parser.close(); 205 | } 206 | } 207 | } 208 | 209 | 210 | } 211 | -------------------------------------------------------------------------------- /src/integration-test/java/org/xbib/elasticsearch/xml/XmlPluginTest.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.xml; 2 | 3 | import org.elasticsearch.action.admin.cluster.node.info.NodesInfoAction; 4 | import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequestBuilder; 5 | import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; 6 | import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; 7 | import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; 8 | import org.elasticsearch.action.index.IndexRequest; 9 | import org.elasticsearch.client.Client; 10 | import org.elasticsearch.common.transport.InetSocketTransportAddress; 11 | import org.junit.Test; 12 | 13 | import java.io.BufferedReader; 14 | import java.io.InputStreamReader; 15 | import java.net.URL; 16 | import java.util.Random; 17 | 18 | import static org.junit.Assert.assertTrue; 19 | 20 | public class XmlPluginTest extends NodeTestUtils { 21 | 22 | @Test 23 | public void testHealthResponse() throws Exception { 24 | InetSocketTransportAddress httpAddress = findHttpAddress(client("1")); 25 | if (httpAddress == null) { 26 | throw new IllegalArgumentException("no HTTP address found"); 27 | } 28 | URL base = new URL("http://" + httpAddress.getHost() + ":" + httpAddress.getPort()); 29 | URL url = new URL(base, "/_cluster/health?xml"); 30 | BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); 31 | String line; 32 | if ((line = reader.readLine()) != null) { 33 | assertTrue(line.startsWith("")); 34 | assertTrue(line.endsWith("")); 35 | } 36 | reader.close(); 37 | } 38 | 39 | @Test 40 | public void testPrettyHealthResponse() throws Exception { 41 | InetSocketTransportAddress httpAddress = findHttpAddress(client("1")); 42 | if (httpAddress == null) { 43 | throw new IllegalArgumentException("no HTTP address found"); 44 | } 45 | URL base = new URL("http://" + httpAddress.getHost() + ":" + httpAddress.getPort()); 46 | URL url = new URL(base, "/_cluster/health?xml&pretty"); 47 | BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); 48 | String line; 49 | // check only first line 50 | if ((line = reader.readLine()) != null) { 51 | assertTrue(line.startsWith("")); 52 | } 53 | reader.close(); 54 | } 55 | 56 | @Test 57 | public void testBigAndFatResponse() throws Exception { 58 | Client client = client("1"); 59 | for (int i = 0; i < 10000; i++) { 60 | client.index(new IndexRequest("test", "test", Integer.toString(i)) 61 | .source("{\"random\":\""+randomString(32)+ " " + randomString(32) + "\"}")).actionGet(); 62 | } 63 | client.admin().indices().refresh(new RefreshRequest("test")).actionGet(); 64 | InetSocketTransportAddress httpAddress = findHttpAddress(client); 65 | if (httpAddress == null) { 66 | throw new IllegalArgumentException("no HTTP address found"); 67 | } 68 | URL base = new URL("http://" + httpAddress.getHost() + ":" + httpAddress.getPort()); 69 | URL url = new URL(base, "/test/test/_search?xml&pretty&size=10000"); 70 | BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); 71 | int count = 0; 72 | String line; 73 | while ((line = reader.readLine()) != null) { 74 | count += line.length(); 75 | } 76 | assertTrue(count >= 2309156); 77 | reader.close(); 78 | client.admin().indices().delete(new DeleteIndexRequest("test")); 79 | } 80 | 81 | private static Random random = new Random(); 82 | 83 | private static char[] numbersAndLetters = ("0123456789abcdefghijklmnopqrstuvwxyz").toCharArray(); 84 | 85 | protected String randomString(int len) { 86 | final char[] buf = new char[len]; 87 | final int n = numbersAndLetters.length - 1; 88 | for (int i = 0; i < buf.length; i++) { 89 | buf[i] = numbersAndLetters[random.nextInt(n)]; 90 | } 91 | return new String(buf); 92 | } 93 | 94 | public static InetSocketTransportAddress findHttpAddress(Client client) { 95 | NodesInfoRequestBuilder nodesInfoRequestBuilder = new NodesInfoRequestBuilder(client, NodesInfoAction.INSTANCE); 96 | nodesInfoRequestBuilder.setHttp(true).setTransport(false); 97 | NodesInfoResponse response = nodesInfoRequestBuilder.execute().actionGet(); 98 | Object obj = response.iterator().next().getHttp().getAddress().publishAddress(); 99 | if (obj instanceof InetSocketTransportAddress) { 100 | return (InetSocketTransportAddress) obj; 101 | } 102 | return null; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/integration-test/resources/dynamic-namespace.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context" : { 3 | "ns" : "http://example.org/" 4 | }, 5 | "ns:foo" : "bar" 6 | } -------------------------------------------------------------------------------- /src/integration-test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/integration-test/resources/test.json: -------------------------------------------------------------------------------- 1 | {"took":10,"timed_out":false,"_shards":{"total":12,"successful":12,"failed":0},"hits":{"total":107,"max_score":6.0844574,"hits":[{"_index":"hbz20121118","_type":"title","_id":"HT010967963","_score":6.0844574, "_source" : {"xbib:updated":"2013-01-24T03:43:42Z","dc:type":{"xbib:recordType":"h","bib:issuance":"multipart monograph","bib:genre":["Inventar","Verzeichnis"]},"dc:identifier":{"xbib:identifierAuthorityMAB":"HT010967963","xbib:sysID":"(DE-605)005237970","xbib:identifierAuthorityISIL":["DE-Kn28","DE-82-707"]},"dc:language":{"xbib:languageISO6392b":"ger","xbib:languageISO6391":"de"},"dc:format":{"dcterms:medium":"print"},"dc:publisher":{"xbib:publisherPlace":"[Köln]","xbib:publisherName":"[Rheinland Verl.]"},"dc:date":{"xbib:date":1977,"dcterms:issued":1977},"dc:subject":[{"dc:subject":["Köln","Architektur","Inventar","Colonia Agrippinensis","Baukunst"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"Köln","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4031483-2"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Architektur","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4002851-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Inventar"}]},{"dc:subject":["Köln","Denkmal","Verzeichnis","Colonia Agrippinensis","Monument","Mahnmal","Denkmäler"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"Köln","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4031483-2"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Denkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4011453-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Verzeichnis"}]},{"dc:subject":["Köln","Kulturdenkmal","Verzeichnis","Colonia Agrippinensis","Denkmal","Denkmalpflege","Kulturstätte","Kulturdenkmäler"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"Köln","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4031483-2"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Kulturdenkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4165967-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Verzeichnis"}]}],"dc:coverage":[{"dcterms:spatial":"Köln"},{"dcterms:spatial":"Köln"},{"dcterms:spatial":"Köln"}],"dc:contributor":{"bib:nameCorporate":"Rheinland / Landeskonservator","xbib:nameCorporateID":"2029876-6"},"dc:title":{"xbib:title":"Denkmälerverzeichnis"},"dc:relation":{"lia:lia":{"lia:access":[{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-Kn28","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-Kn28 MAG Ed 1532","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"Ed 1532","lia:number":"MAG"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-82-707","lia:authority":"ISIL"}}]}}}},{"_index":"hbz20121118","_type":"title","_id":"HT016444856","_score":5.8594685, "_source" : {"xbib:updated":"2012-11-28T19:05:58Z","dc:type":{"xbib:recordType":"h","bib:issuance":"multipart monograph","bib:genre":"Führer"},"dc:identifier":{"xbib:identifierAuthorityMAB":"HT016444856","xbib:identifierAuthorityDNB":"1004377207","xbib:identifierAuthorityEKI":"DNB1004377207","xbib:sysID":"(DE-605)018139165","xbib:identifierAuthorityISIL":["DE-Kn28","DE-5","DE-38","DE-Kn3"]},"dc:language":{"xbib:languageISO6392b":"ger","xbib:languageISO6391":"de"},"dc:format":{"dcterms:medium":["print","paper"]},"dc:subject":[{"dc:subject":"NWBib-61","xbib:subject":{"xbib:subjectAuthority":"NWBIB","xbib:subjectValue":"NWBib-61"}},{"dc:subject":["99","Köln"],"xbib:subject":{"xbib:subjectAuthority":"NWBIB","xbib:subjectValue":["99","Köln"]}},{"dc:subject":"102070","xbib:subject":{"xbib:subjectAuthority":"NWBIB","xbib:subjectValue":"102070"}},{"dc:subject":["Köln","Kulturdenkmal","Führer","Colonia Agrippinensis","Denkmal","Denkmalpflege","Kulturstätte","Kulturdenkmäler"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"Köln","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4031483-2"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Kulturdenkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4165967-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Führer"}]}],"dc:description":{"xbib:creatorDescription":"Stadt Köln. Markus Eckstein","dcterms:extent":"21 cm"},"dc:publisher":{"xbib:publisherPlace":"Köln","xbib:publisherName":"Bachem"},"dc:date":{"xbib:date":2010,"dcterms:issued":2010},"dc:relation":[{"xbib:relationType":"note","xbib:relationName":"Erschienen","xbib:relationValue":"Bd 1 -"},{"lia:lia":{"lia:access":[{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-Kn28","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-Kn28 MAG s. Einzelbände","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"s. Einzelbände","lia:number":"MAG"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-5","lia:authority":"ISIL"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-38","lia:authority":"ISIL"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-Kn3","lia:authority":"ISIL"}}]}}],"dc:coverage":{"dcterms:spatial":"Köln"},"dc:contributor":{"bib:namePersonal":"Eckstein, Markus <1964->","xbib:namePersonalID":"12965342X","xbib:namePersonalBirthYear":"1964","xbib:namePersonalRole":"cre","xbib:namePersonalAlt":"Ėckštajn, Markus"},"dc:creator":{"bib:namePersonal":"Eckstein, Markus <1964->","xbib:namePersonalID":"12965342X","xbib:namePersonalAlt":"Ėckštajn, Markus"},"dc:title":{"xbib:title":"Kulturpfade Köln"}}},{"_index":"hbz20121118","_type":"title","_id":"HT004429504","_score":5.62819, "_source" : {"xbib:updated":"2012-11-28T18:18:34Z","dc:type":{"xbib:recordType":"h","bib:issuance":"multipart monograph","bib:genre":"Führer"},"dc:identifier":{"xbib:identifierAuthorityMAB":"HT004429504","xbib:identifierAuthorityEKI":"HBZHT004429504","xbib:sysID":"(DE-605)004918285","xbib:identifierAuthorityISIL":["DE-5-11","DE-5","DE-38"]},"dc:format":{"dcterms:medium":"print"},"dc:subject":[{"dc:subject":"NWBib-61","xbib:subject":{"xbib:subjectAuthority":"NWBIB","xbib:subjectValue":"NWBib-61"}},{"dc:subject":["99","Köln"],"xbib:subject":{"xbib:subjectAuthority":"NWBIB","xbib:subjectValue":["99","Köln"]}},{"dc:subject":"102070","xbib:subject":{"xbib:subjectAuthority":"NWBIB","xbib:subjectValue":"102070"}},{"dc:subject":["Köln","Kulturdenkmal","Führer","Colonia Agrippinensis","Denkmal","Denkmalpflege","Kulturstätte","Kulturdenkmäler"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"Köln","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4031483-2"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Kulturdenkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4165967-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Führer"}]}],"dc:contributor":[{"bib:namePersonal":"Hagspiel, Wolfram <1952->","xbib:namePersonalID":"109854942","xbib:namePersonalBirthYear":"1952","xbib:namePersonalRole":"cre"},{"bib:namePersonal":"Koller-Schmitz, Susanne","xbib:namePersonalID":"188259252","xbib:namePersonalRole":"cre","xbib:namePersonalAlt":"Schmitz, Susanne Koller-"}],"dc:creator":[{"bib:namePersonal":"Hagspiel, Wolfram <1952->","xbib:namePersonalID":"109854942"},{"bib:namePersonal":"Koller-Schmitz, Susanne","xbib:namePersonalID":"188259252","xbib:namePersonalAlt":"Schmitz, Susanne Koller-"}],"dc:description":{"xbib:creatorDescription":"[Hrsg.: Stadt Köln, Nachrichtenamt ...]"},"dc:publisher":{"xbib:publisherPlace":"Köln"},"dc:coverage":{"dcterms:spatial":"Köln"},"dc:title":{"xbib:title":"Kulturpfade"},"dc:relation":{"lia:lia":{"lia:access":[{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-5-11","lia:authority":"ISIL"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-5","lia:authority":"ISIL"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-38","lia:authority":"ISIL"}}]}}}},{"_index":"hbz20121118","_type":"title","_id":"HT014250856","_score":5.5665355, "_source" : {"xbib:updated":"2012-11-28T18:46:20Z","dc:type":{"xbib:recordType":"h","bib:issuance":"monographic"},"dc:identifier":{"xbib:identifierAuthorityMAB":"HT014250856","xbib:sysID":"(DE-605)013380724","xbib:identifierAuthorityISIL":"DE-38"},"dc:language":{"xbib:languageISO6392b":"ger","xbib:languageISO6391":"de"},"dc:format":{"dcterms:medium":["print","paper"]},"dc:description":{"xbib:creatorDescription":"Friedrich Haupt","dcterms:extent":["[12] S.","Ill.","27 cm"],"xbib:description":"94,P01"},"dc:publisher":{"xbib:publisherPlace":"Köln","xbib:publisherName":"[Gymnasium Kreuzgasse]"},"dc:date":{"xbib:date":1978,"dcterms:issued":1978},"dc:source":{"xbib:sourceTitle":"Festschrift zur 150-Jahr-Feier des Gymnasiums Kreuzgasse, Köln"},"dc:contributor":{"bib:namePersonal":"Haupt, Friedrich","xbib:namePersonalID":"10057694X","xbib:namePersonalRole":"cre"},"dc:creator":{"bib:namePersonal":"Haupt, Friedrich","xbib:namePersonalID":"10057694X"},"dc:title":{"xbib:title":"Melaten","xbib:titleSub":"Friedhof und Kulturdenkmal"},"dc:relation":{"lia:lia":{"lia:access":{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-38","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-38 00000001 RHKAS1661","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"RHKAS1661","lia:number":"00000001"}}}}}},{"_index":"hbz20121118","_type":"title","_id":"TT002559044","_score":5.487817, "_source" : {"xbib:updated":"2012-11-28T19:02:05Z","dc:type":{"xbib:recordType":"h","bib:issuance":"monographic"},"dc:identifier":{"xbib:identifierAuthorityMAB":"TT002559044","xbib:sysID":"(DE-605)016823971","xbib:identifierAuthorityISIL":"DE-Kn3"},"dc:language":{"xbib:languageISO6392b":"ger","xbib:languageISO6391":"de"},"dc:format":{"dcterms:medium":["print","paper"]},"dc:publisher":{"xbib:publisherPlace":"KÖLN"},"dc:date":{"xbib:date":1978,"dcterms:issued":1978},"dc:description":{"dcterms:extent":"6 BL. MIT ABB."},"dc:source":{"xbib:sourceTitle":"FESTSCHRIFT ZUR 150-JAHR-FEIER DES GYMNASIUMS KREUZGASSE, KÖLN"},"dc:contributor":{"bib:namePersonal":"Haupt, Friedrich","xbib:namePersonalID":"10057694X","xbib:namePersonalRole":"cre"},"dc:creator":{"bib:namePersonal":"Haupt, Friedrich","xbib:namePersonalID":"10057694X"},"dc:title":{"xbib:title":"MELATEN - FRIEDHOF UND KULTURDENKMAL","xbib:titleSub":"VON FRIEDRICH HAUPT"},"dc:relation":{"lia:lia":{"lia:access":{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-Kn3","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-Kn3 50 GT KÖLN 69 1978","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"GT KÖLN 69 1978","lia:number":"50"}}}}}},{"_index":"hbz20121118","_type":"title","_id":"HT007460854","_score":4.9246664, "_source" : {"xbib:updated":"2012-11-28T18:13:10Z","dc:type":{"xbib:recordType":"h","bib:issuance":"monographic","bib:genre":"Bildband"},"dc:identifier":{"xbib:identifierAuthorityMAB":"HT007460854","xbib:sysID":"(DE-605)002860849","xbib:identifierAuthorityISIL":["DE-929","DE-Kn3"]},"dc:format":{"dcterms:medium":"print"},"dc:publisher":{"xbib:publisherPlace":"Köln","xbib:publisherName":"DuMont Schauberg"},"dc:date":{"xbib:date":1955,"dcterms:issued":1955},"dc:description":{"dcterms:extent":"48 S. : Ill."},"dc:subject":[{"dc:subject":"500","xbib:subject":{"xbib:subjectAuthority":"RPB","xbib:subjectValue":"500"}},{"dc:subject":["Köln","Kulturdenkmal","Geschichte","Bildband","Colonia Agrippinensis","Denkmal","Denkmalpflege","Kulturstätte","Kulturdenkmäler"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"Köln","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4031483-2"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Kulturdenkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4165967-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"temporal","xbib:subjectValue":"Geschichte"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Bildband"}]}],"dc:coverage":[{"dcterms:spatial":"Köln"},{"dcterms:temporal":"Geschichte"}],"dc:contributor":{"bib:namePersonal":"Förster, Otto H. <1894-1975>","xbib:namePersonalID":"118692054","xbib:namePersonalBirthYear":"1894","xbib:namePersonalDeathYear":"1975","xbib:namePersonalRole":"cre","xbib:namePersonalAlt":["Förster, Otto Helmut","Förster, Otto-Helmut","Förster, Otto"]},"dc:creator":{"bib:namePersonal":"Förster, Otto H. <1894-1975>","xbib:namePersonalID":"118692054","xbib:namePersonalAlt":["Förster, Otto Helmut","Förster, Otto-Helmut","Förster, Otto"]},"dc:title":{"xbib:title":"Köln","xbib:titleSub":"Geschichte und Gesichte"},"dc:relation":{"lia:lia":{"lia:access":[{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-929","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-929 00000000 P = P 4611","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"P = P 4611","lia:number":"00000000"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-Kn3","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-Kn3 50 GT KÖLN 5 1955","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"GT KÖLN 5 1955","lia:number":"50"}}]}}}},{"_index":"hbz20121118","_type":"title","_id":"HT015031803","_score":4.365741, "_source" : {"xbib:updated":"2012-11-28T17:44:36Z","dc:type":{"xbib:recordType":"h","bib:issuance":"monographic","bib:genre":"Wörterbuch"},"dc:identifier":{"xbib:identifierAuthorityMAB":"HT015031803","xbib:identifierAuthorityEKI":"HBZHT015031803","xbib:identifierAuthorityOriginISBN":["978-3-89836-609-0","3-89836-609-X"],"xbib:identifierAuthorityEAN":"9783898366090","xbib:identifierAuthorityISBN":"389836609X","xbib:sysID":"(DE-605)015622949","xbib:identifierAuthorityISIL":["DE-5-99","DE-5","DE-385","DE-1116"]},"dc:language":{"xbib:languageISO6392b":"ger","xbib:languageISO6391":"de"},"dc:format":{"dcterms:medium":["print","paper"]},"dc:description":{"xbib:creatorDescription":"Josef Guter","dcterms:extent":["317, [50] S.","zahlr. Ill.","31 cm"],"xbib:description":["09609","9783898366090","07,N08,2466"]},"dc:publisher":{"xbib:publisherPlace":"Köln","xbib:publisherName":"Komet"},"dc:date":{"xbib:date":2007,"dcterms:issued":2007},"dc:relation":[{"xbib:relationType":"resource","xbib:relationValueID":"http://deposit.d-nb.de/cgi-bin/dokserv?id=2908244&prov=M&dok_var=1&dok_ext=htm","xbib:relationName":"2","xbib:materialsSpecified":"Inhaltstext","xbib:uniformResourceIdentifier":"http://deposit.d-nb.de/cgi-bin/dokserv?id=2908244&prov=M&dok_var=1&dok_ext=htm","xbib:electronicFormatType":"text/html"},{"lia:lia":{"lia:access":[{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"site-access","lia:library":{"lia:name":"DE-605","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-605 http://deposit.d-nb.de/cgi-bin/dokserv?id=2908244&prov=M&dok_var=1&dok_ext=htm","lia:type":"electronic-resource","lia:preferredTransport":"electronic","lia:preferredDelivery":"electronic","lia:address":"http://deposit.d-nb.de/cgi-bin/dokserv?id=2908244&prov=M&dok_var=1&dok_ext=htm","lia:label":"Inhaltstext"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-5-99","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-5-99 00057000 T52:1 Guter","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"T52:1 Guter","lia:number":"00057000"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-5","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-5 00000000 W 4' 2009/151","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"W 4' 2009/151","lia:number":"00000000"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-385","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-385 27 BEK/od30500","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"BEK/od30500","lia:number":"27"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-1116","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-1116 00023 BIL-200","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"BIL-200","lia:number":"00023"}}]}}],"dc:subject":{"dc:subject":["China","Kulturdenkmal","Wörterbuch","Rotchina","Volksrepublik","Volksrepublik China","Zhongguo","Denkmal","Denkmalpflege","Kulturstätte","Kulturdenkmäler"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"China","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4009937-4"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Kulturdenkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4165967-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Wörterbuch"}]},"dc:coverage":{"dcterms:spatial":"China"},"dc:contributor":{"bib:namePersonal":"Guter, Josef <1929->","xbib:namePersonalID":"115605673","xbib:namePersonalBirthYear":"1929","xbib:namePersonalRole":"cre"},"dc:creator":{"bib:namePersonal":"Guter, Josef <1929->","xbib:namePersonalID":"115605673"},"dc:title":{"xbib:title":"Das Lexikon der chinesischen Kulturstätten"}}},{"_index":"hbz20121118","_type":"title","_id":"TT001861652","_score":4.337492, "_source" : {"xbib:updated":"2012-11-28T21:26:59Z","dc:type":{"xbib:recordType":"h","bib:issuance":"multipart monograph","bib:genre":"Verzeichnis"},"dc:identifier":{"xbib:identifierAuthorityMAB":"TT001861652","xbib:identifierAuthorityMABWhole":"TT001830414","xbib:sysID":"(DE-605)014946051","xbib:identifierAuthorityISIL":"DE-Kn28"},"dc:format":{"dcterms:medium":["print","paper"]},"dc:description":{"xbib:creatorDescription":"[hrsg. im Auftr. d. Ministeriums für Stadtenwicklung, Wohnen und Verkehr des Landes Nordrhein-Westfalen vom Landschaftsverband Rheinland, Rhein. Amt für Denkmalpflege. Udo Mainzer]"},"dc:publisher":{"xbib:publisherPlace":"Köln [i.e. Pulheim]","xbib:publisherName":"Rheinland-Verl. [u.a.]"},"dc:relation":[{"xbib:relationType":"series","xbib:relationName":"Denkmaltopographie Bundesrepublik Deutschland ; 1992","xbib:relationValueID":"TT001830414","xbib:relationValue":"1992"},{"lia:lia":{"lia:access":{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-Kn28","lia:authority":"ISIL"}}}}],"dc:title":[{"xbib:titleWhole":"Denkmaltopographie Bundesrepublik Deutschland ; 1992"},{"xbib:title":"Denkmäler im Rheinland"}],"dc:subject":{"dc:subject":["Rheinland","Kulturdenkmal","Verzeichnis","Rheinlande","im engeren Sinn","Denkmal","Denkmalpflege","Kulturstätte","Kulturdenkmäler"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"Rheinland","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4049788-4"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Kulturdenkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4165967-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Verzeichnis"}]},"dc:coverage":{"dcterms:spatial":"Rheinland"},"dc:contributor":[{"bib:namePersonal":"Mainzer, Udo <1945->","xbib:namePersonalID":"115734988","xbib:namePersonalBirthYear":"1945","xbib:namePersonalRole":"edt"},{"bib:nameCorporate":"Rheinland / Amt für Denkmalpflege","xbib:nameCorporateID":"2066890-9","xbib:nameCorporateAlt":["Rheinisches Amt für Denkmalpflege","Amt für Denkmalpflege","LVR-Amt für Denkmalpflege","LVR-Amt für Denkmalpflege im Rheinland","Denkmalpflege","Rheinische Denkmalpflege","Amt für Denkmalpflege im Rheinland"]}]}},{"_index":"hbz20121118","_type":"title","_id":"TT001754227","_score":4.298668, "_source" : {"xbib:updated":"2012-11-28T18:51:10Z","dc:type":{"xbib:recordType":"h","bib:issuance":"monographic","bib:genre":"Reisebericht <1660>"},"dc:identifier":{"xbib:identifierAuthorityMAB":"TT001754227","xbib:identifierAuthorityOriginISBN":"3-412-16701-0","xbib:identifierAuthorityEAN":"9783412167011","xbib:identifierAuthorityISBN":"3412167010","xbib:sysID":"(DE-605)014838583","xbib:identifierAuthorityISIL":["DE-Kn28","DE-Kn3","DE-Due18"]},"dc:format":{"dcterms:medium":["print","paper"]},"dc:description":{"xbib:creatorDescription":"Udo Kindermann","dcterms:extent":"VII, 527 S.","xbib:description":"Einheitssacht. des komm. Werkes: Papebroch, Daniel: Diarium itineris romani anno 1660 suscepti. - Text in dt. und lat. Sprache"},"dc:publisher":{"xbib:publisherPlace":"Köln [u.a.]","xbib:publisherName":"Böhlau"},"dc:date":{"xbib:date":2002,"dcterms:issued":2002},"dc:subject":{"dc:subject":["Europa","Kulturdenkmal","Reisebericht <1660>","Abendland","Okzident","Denkmal","Denkmalpflege","Kulturstätte","Kulturdenkmäler"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"spatial","xbib:subjectValue":"Europa","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4015701-5"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Kulturdenkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4165967-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"genre","xbib:subjectValue":"Reisebericht <1660>"}]},"dc:coverage":{"dcterms:spatial":"Europa"},"dc:contributor":{"bib:namePersonal":"Kindermann, Udo <1941->","xbib:namePersonalID":"10718978X","xbib:namePersonalBirthYear":"1941","xbib:namePersonalRole":"cre"},"dc:creator":{"bib:namePersonal":"Kindermann, Udo <1941->","xbib:namePersonalID":"10718978X"},"dc:title":{"xbib:title":"Kunstdenkmäler zwischen Antwerpen und Trient","xbib:titleSub":["Beschreibungen und Bewertungen des Jesuiten Daniel Papebroch aus dem Jahre 1660 ; Erstedition, Übersetzung, Kommentar","Diarium itineris romani anno 1660 suscepti"]},"dc:relation":{"lia:lia":{"lia:access":[{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-Kn28","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-Kn28 MAG Fbb 9506","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"Fbb 9506","lia:number":"MAG"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-Kn3","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-Kn3 50 FW 3 DEUTSC 2002","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"FW 3 DEUTSC 2002","lia:number":"50"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-Due18","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-Due18 Le, 7010","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"Le, 7010"}}]}}}},{"_index":"hbz20121118","_type":"title","_id":"HT003067207","_score":4.092424, "_source" : {"xbib:updated":"2013-05-20T02:22:06Z","dc:type":{"xbib:recordType":"h","bib:issuance":"monographic"},"dc:identifier":{"xbib:identifierAuthorityMAB":"HT003067207","xbib:identifierAuthorityEKI":"HBZHT003067207","xbib:identifierAuthorityMABWhole":"HT001240673","xbib:identifierAuthorityOriginISBN":"3-555-00724-6","xbib:identifierAuthorityEAN":"9783555007243","xbib:identifierAuthorityISBN":"3555007246","xbib:sysID":"(DE-605)006275125","xbib:identifierAuthorityISIL":["DE-38","DE-5-34","DE-294-39","DE-290","DE-294","DE-361","DE-5","DE-6","DE-6-016","DE-6-244","DE-294-30","DE-82","DE-5-82","DE-708","DE-385","DE-386-02","DE-64"]},"dc:language":{"xbib:languageISO6392b":"ger","xbib:languageISO6391":"de"},"dc:format":{"dcterms:medium":"print"},"dc:description":{"xbib:creatorDescription":"von Ernst-Rainer Hönes","dcterms:extent":"LVI, 284 S."},"dc:publisher":{"xbib:publisherPlace":"Köln","xbib:publisherName":"Kohlhammer [u.a.]"},"dc:date":{"xbib:date":1987,"dcterms:issued":1987},"dc:relation":[{"xbib:relationType":"series","xbib:relationName":"Schriften zur öffentlichen Verwaltung ; 27","xbib:relationValueID":"HT001240673","xbib:relationValue":"27"},{"lia:lia":{"lia:access":[{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-38","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-38 00000001 9Y5812","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"9Y5812","lia:number":"00000001"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-5-34","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-5-34 00013001 Oi 1356/46","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"Oi 1356/46","lia:number":"00013001"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-294-39","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-294-39 00039000 43/Y/527","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"43/Y/527","lia:number":"00039000"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-290","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-290 00010010 472/Hoen","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"472/Hoen","lia:number":"00010010"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-290","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-290 00000001 G 13068","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"G 13068","lia:number":"00000001"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-294","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-294 00000033 FLA1471","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"FLA1471","lia:number":"00000033"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-361","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-361 00000011 KH243 H694","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"KH243 H694","lia:number":"00000011"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-5","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-5 00000010 87/6134","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"87/6134","lia:number":"00000010"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-6","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-6 00000040 3D 37888","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"3D 37888","lia:number":"00000040"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-6-016","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-6-016 00025001 VwR XII GH 8","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"VwR XII GH 8","lia:number":"00025001"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-6-244","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-6-244 00029004 R-56 S 8","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"R-56 S 8","lia:number":"00029004"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-294-30","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-294-30 00030000 G DA 16","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"G DA 16","lia:number":"00030000"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-82","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-82 00000000 OA7054-27+1","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"OA7054-27+1","lia:number":"00000000"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"restricted","lia:library":{"lia:name":"DE-5-82","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-5-82 00120001 1.4-121","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"1.4-121","lia:number":"00120001"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-708","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-708 30 QSL/HOE","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"QSL/HOE","lia:number":"30"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":"copy","lia:library":{"lia:name":"DE-385","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-385 60 AS/r6261-27","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"AS/r6261-27","lia:number":"60"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:service":["inter-library-loan","copy"],"lia:library":{"lia:name":"DE-386-02","lia:authority":"ISIL"},"lia:item":{"lia:identifier":"DE-386-02 GEB02 ARB 907/006","lia:type":"hard-cover","lia:preferredTransport":"physical","lia:preferredDelivery":"physical","lia:shelfmark":"ARB 907/006","lia:number":"GEB02"}},{"lia:name":"DE-605","lia:authority":"ISIL","lia:library":{"lia:name":"DE-64","lia:authority":"ISIL"}}]}}],"dc:title":[{"xbib:titleWhole":"Schriften zur öffentlichen Verwaltung ; 27"},{"xbib:title":"Die Unterschutzstellung von Kulturdenkmälern"}],"dc:subject":{"dc:subject":["Kulturdenkmal","Denkmalschutz","Denkmal","Denkmalpflege","Kulturstätte","Kulturdenkmäler","Denkmalschutzrecht","Denkmalrecht"],"xbib:subject":[{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Kulturdenkmal","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4165967-3"},{"xbib:subjectAuthority":"RSWK","xbib:subjectType":"topic","xbib:subjectValue":"Denkmalschutz","xbib:subjectIDAuthority":"GND","xbib:subjectID":"4011457-0"}]},"dc:contributor":{"bib:namePersonal":"Hönes, Ernst-Rainer <1942->","xbib:namePersonalID":"138575398","xbib:namePersonalBirthYear":"1942","xbib:namePersonalRole":"cre"},"dc:creator":{"bib:namePersonal":"Hönes, Ernst-Rainer <1942->","xbib:namePersonalID":"138575398"}}}]}} -------------------------------------------------------------------------------- /src/integration-test/resources/xml-namespaces.properties: -------------------------------------------------------------------------------- 1 | # XML namespaces 2 | xml = http://www.w3.org/XML/1998/namespace 3 | xsl = http://www.w3.org/1999/XSL/Transform 4 | 5 | # Apache 6 | xalan = http://xml.apache.org/xslt 7 | 8 | # W3C Atom 9 | atom = http://www.w3.org/2005/Atom 10 | 11 | # some RDF namespaces 12 | rdf = http://www.w3.org/1999/02/22-rdf-syntax-ns# 13 | rdfs = http://www.w3.org/2000/01/rdf-schema# 14 | owl = http://www.w3.org/2002/07/owl# 15 | foaf = http://xmlns.com/foaf/0.1/ 16 | 17 | # Dublin Core 18 | # http://dublincore.org/documents/dcmi-namespace/ 19 | dc = http://purl.org/dc/elements/1.1/ 20 | dcterms = http://purl.org/dc/terms/ 21 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/XmlXContentBuilder.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.common.xcontent; 2 | 3 | import com.google.common.base.Charsets; 4 | import org.apache.lucene.util.BytesRef; 5 | import org.elasticsearch.common.Strings; 6 | import org.elasticsearch.common.bytes.BytesArray; 7 | import org.elasticsearch.common.bytes.BytesReference; 8 | import org.elasticsearch.common.geo.GeoPoint; 9 | import org.elasticsearch.common.io.BytesStream; 10 | import org.elasticsearch.common.io.stream.BytesStreamOutput; 11 | import org.elasticsearch.common.text.Text; 12 | import org.elasticsearch.common.unit.ByteSizeValue; 13 | import org.elasticsearch.common.unit.TimeValue; 14 | import org.elasticsearch.common.xcontent.XContent; 15 | import org.elasticsearch.common.xcontent.XContentBuilderString; 16 | import org.elasticsearch.common.xcontent.XContentGenerator; 17 | import org.elasticsearch.common.xcontent.XContentParser; 18 | import org.elasticsearch.common.xcontent.XContentType; 19 | import org.joda.time.DateTimeZone; 20 | import org.joda.time.ReadableInstant; 21 | import org.joda.time.format.DateTimeFormatter; 22 | import org.joda.time.format.ISODateTimeFormat; 23 | 24 | import java.io.IOException; 25 | import java.io.OutputStream; 26 | import java.math.BigDecimal; 27 | import java.math.RoundingMode; 28 | import java.util.Calendar; 29 | import java.util.Date; 30 | import java.util.Map; 31 | 32 | public final class XmlXContentBuilder implements BytesStream { 33 | 34 | public static enum FieldCaseConversion { 35 | /** 36 | * No conversion will occur. 37 | */ 38 | NONE, 39 | /** 40 | * Camel Case will be converted to Underscore casing. 41 | */ 42 | UNDERSCORE, 43 | /** 44 | * Underscore will be converted to Camel case. 45 | */ 46 | CAMELCASE 47 | } 48 | 49 | public final static DateTimeFormatter defaultDatePrinter = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC); 50 | 51 | protected static FieldCaseConversion globalFieldCaseConversion = FieldCaseConversion.NONE; 52 | 53 | public static void globalFieldCaseConversion(FieldCaseConversion globalFieldCaseConversion) { 54 | XmlXContentBuilder.globalFieldCaseConversion = globalFieldCaseConversion; 55 | } 56 | 57 | public static XmlXContentBuilder builder(XContent xContent) throws IOException { 58 | return new XmlXContentBuilder(xContent, new BytesStreamOutput()); 59 | } 60 | 61 | private XContentGenerator generator; 62 | 63 | private final OutputStream bos; 64 | 65 | private FieldCaseConversion fieldCaseConversion = globalFieldCaseConversion; 66 | 67 | private StringBuilder cachedStringBuilder; 68 | 69 | private boolean humanReadable = false; 70 | 71 | /** 72 | * Constructs a new builder using the provided xcontent and an OutputStream. Make sure 73 | * to call {@link #close()} when the builder is done with. 74 | */ 75 | public XmlXContentBuilder(XContent xContent, OutputStream bos) throws IOException { 76 | this.bos = bos; 77 | this.generator = xContent.createGenerator(bos); 78 | } 79 | 80 | public XmlXContentBuilder fieldCaseConversion(FieldCaseConversion fieldCaseConversion) { 81 | this.fieldCaseConversion = fieldCaseConversion; 82 | return this; 83 | } 84 | 85 | public XContentType contentType() { 86 | return generator.contentType(); 87 | } 88 | 89 | public XmlXContentBuilder prettyPrint() { 90 | generator.usePrettyPrint(); 91 | return this; 92 | } 93 | 94 | public XmlXContentBuilder lfAtEnd() { 95 | generator.usePrintLineFeedAtEnd(); 96 | return this; 97 | } 98 | 99 | public XmlXContentBuilder humanReadable(boolean humanReadable) { 100 | this.humanReadable = humanReadable; 101 | return this; 102 | } 103 | 104 | public boolean humanReadable() { 105 | return this.humanReadable; 106 | } 107 | 108 | // TODO make ToXContent understand XML 109 | 110 | /*public XContentBuilder field(String name, ToXContent xContent) throws IOException { 111 | field(name); 112 | xContent.toXContent(this, ToXContent.EMPTY_PARAMS); 113 | return this; 114 | } 115 | 116 | public XContentBuilder field(String name, ToXContent xContent, ToXContent.Params params) throws IOException { 117 | field(name); 118 | xContent.toXContent(this, params); 119 | return this; 120 | }*/ 121 | 122 | public XmlXContentBuilder startObject(String name) throws IOException { 123 | field(name); 124 | startObject(); 125 | return this; 126 | } 127 | 128 | public XmlXContentBuilder startObject(String name, FieldCaseConversion conversion) throws IOException { 129 | field(name, conversion); 130 | startObject(); 131 | return this; 132 | } 133 | 134 | public XmlXContentBuilder startObject(XContentBuilderString name) throws IOException { 135 | field(name); 136 | startObject(); 137 | return this; 138 | } 139 | 140 | public XmlXContentBuilder startObject(XContentBuilderString name, FieldCaseConversion conversion) throws IOException { 141 | field(name, conversion); 142 | startObject(); 143 | return this; 144 | } 145 | 146 | public XmlXContentBuilder startObject() throws IOException { 147 | generator.writeStartObject(); 148 | return this; 149 | } 150 | 151 | public XmlXContentBuilder endObject() throws IOException { 152 | generator.writeEndObject(); 153 | return this; 154 | } 155 | 156 | public XmlXContentBuilder array(String name, String... values) throws IOException { 157 | startArray(name); 158 | for (String value : values) { 159 | value(value); 160 | } 161 | endArray(); 162 | return this; 163 | } 164 | 165 | public XmlXContentBuilder array(XContentBuilderString name, String... values) throws IOException { 166 | startArray(name); 167 | for (String value : values) { 168 | value(value); 169 | } 170 | endArray(); 171 | return this; 172 | } 173 | 174 | public XmlXContentBuilder array(String name, Object... values) throws IOException { 175 | startArray(name); 176 | for (Object value : values) { 177 | value(value); 178 | } 179 | endArray(); 180 | return this; 181 | } 182 | 183 | public XmlXContentBuilder array(XContentBuilderString name, Object... values) throws IOException { 184 | startArray(name); 185 | for (Object value : values) { 186 | value(value); 187 | } 188 | endArray(); 189 | return this; 190 | } 191 | 192 | public XmlXContentBuilder startArray(String name, FieldCaseConversion conversion) throws IOException { 193 | field(name, conversion); 194 | startArray(); 195 | return this; 196 | } 197 | 198 | public XmlXContentBuilder startArray(String name) throws IOException { 199 | field(name); 200 | startArray(); 201 | return this; 202 | } 203 | 204 | public XmlXContentBuilder startArray(XContentBuilderString name) throws IOException { 205 | field(name); 206 | startArray(); 207 | return this; 208 | } 209 | 210 | public XmlXContentBuilder startArray() throws IOException { 211 | generator.writeStartArray(); 212 | return this; 213 | } 214 | 215 | public XmlXContentBuilder endArray() throws IOException { 216 | generator.writeEndArray(); 217 | return this; 218 | } 219 | 220 | public XmlXContentBuilder field(XContentBuilderString name) throws IOException { 221 | if (fieldCaseConversion == FieldCaseConversion.UNDERSCORE) { 222 | generator.writeFieldName(name.underscore()); 223 | } else if (fieldCaseConversion == FieldCaseConversion.CAMELCASE) { 224 | generator.writeFieldName(name.camelCase()); 225 | } else { 226 | generator.writeFieldName(name.underscore()); 227 | } 228 | return this; 229 | } 230 | 231 | public XmlXContentBuilder field(XContentBuilderString name, FieldCaseConversion conversion) throws IOException { 232 | if (conversion == FieldCaseConversion.UNDERSCORE) { 233 | generator.writeFieldName(name.underscore()); 234 | } else if (conversion == FieldCaseConversion.CAMELCASE) { 235 | generator.writeFieldName(name.camelCase()); 236 | } else { 237 | generator.writeFieldName(name.underscore()); 238 | } 239 | return this; 240 | } 241 | 242 | public XmlXContentBuilder field(String name) throws IOException { 243 | if (fieldCaseConversion == FieldCaseConversion.UNDERSCORE) { 244 | if (cachedStringBuilder == null) { 245 | cachedStringBuilder = new StringBuilder(); 246 | } 247 | name = Strings.toUnderscoreCase(name, cachedStringBuilder); 248 | } else if (fieldCaseConversion == FieldCaseConversion.CAMELCASE) { 249 | if (cachedStringBuilder == null) { 250 | cachedStringBuilder = new StringBuilder(); 251 | } 252 | name = Strings.toCamelCase(name, cachedStringBuilder); 253 | } 254 | generator.writeFieldName(name); 255 | return this; 256 | } 257 | 258 | public XmlXContentBuilder field(String name, FieldCaseConversion conversion) throws IOException { 259 | if (conversion == FieldCaseConversion.UNDERSCORE) { 260 | if (cachedStringBuilder == null) { 261 | cachedStringBuilder = new StringBuilder(); 262 | } 263 | name = Strings.toUnderscoreCase(name, cachedStringBuilder); 264 | } else if (conversion == FieldCaseConversion.CAMELCASE) { 265 | if (cachedStringBuilder == null) { 266 | cachedStringBuilder = new StringBuilder(); 267 | } 268 | name = Strings.toCamelCase(name, cachedStringBuilder); 269 | } 270 | generator.writeFieldName(name); 271 | return this; 272 | } 273 | 274 | public XmlXContentBuilder field(String name, char[] value, int offset, int length) throws IOException { 275 | field(name); 276 | if (value == null) { 277 | generator.writeNull(); 278 | } else { 279 | generator.writeString(value, offset, length); 280 | } 281 | return this; 282 | } 283 | 284 | public XmlXContentBuilder field(XContentBuilderString name, char[] value, int offset, int length) throws IOException { 285 | field(name); 286 | if (value == null) { 287 | generator.writeNull(); 288 | } else { 289 | generator.writeString(value, offset, length); 290 | } 291 | return this; 292 | } 293 | 294 | public XmlXContentBuilder field(String name, String value) throws IOException { 295 | field(name); 296 | if (value == null) { 297 | generator.writeNull(); 298 | } else { 299 | generator.writeString(value); 300 | } 301 | return this; 302 | } 303 | 304 | public XmlXContentBuilder field(String name, String value, FieldCaseConversion conversion) throws IOException { 305 | field(name, conversion); 306 | if (value == null) { 307 | generator.writeNull(); 308 | } else { 309 | generator.writeString(value); 310 | } 311 | return this; 312 | } 313 | 314 | public XmlXContentBuilder field(XContentBuilderString name, String value) throws IOException { 315 | field(name); 316 | if (value == null) { 317 | generator.writeNull(); 318 | } else { 319 | generator.writeString(value); 320 | } 321 | return this; 322 | } 323 | 324 | public XmlXContentBuilder field(XContentBuilderString name, String value, FieldCaseConversion conversion) throws IOException { 325 | field(name, conversion); 326 | if (value == null) { 327 | generator.writeNull(); 328 | } else { 329 | generator.writeString(value); 330 | } 331 | return this; 332 | } 333 | 334 | public XmlXContentBuilder field(String name, Integer value) throws IOException { 335 | field(name); 336 | if (value == null) { 337 | generator.writeNull(); 338 | } else { 339 | generator.writeNumber(value.intValue()); 340 | } 341 | return this; 342 | } 343 | 344 | public XmlXContentBuilder field(XContentBuilderString name, Integer value) throws IOException { 345 | field(name); 346 | if (value == null) { 347 | generator.writeNull(); 348 | } else { 349 | generator.writeNumber(value.intValue()); 350 | } 351 | return this; 352 | } 353 | 354 | public XmlXContentBuilder field(String name, int value) throws IOException { 355 | field(name); 356 | generator.writeNumber(value); 357 | return this; 358 | } 359 | 360 | public XmlXContentBuilder field(XContentBuilderString name, int value) throws IOException { 361 | field(name); 362 | generator.writeNumber(value); 363 | return this; 364 | } 365 | 366 | public XmlXContentBuilder field(String name, Long value) throws IOException { 367 | field(name); 368 | if (value == null) { 369 | generator.writeNull(); 370 | } else { 371 | generator.writeNumber(value.longValue()); 372 | } 373 | return this; 374 | } 375 | 376 | public XmlXContentBuilder field(XContentBuilderString name, Long value) throws IOException { 377 | field(name); 378 | if (value == null) { 379 | generator.writeNull(); 380 | } else { 381 | generator.writeNumber(value.longValue()); 382 | } 383 | return this; 384 | } 385 | 386 | public XmlXContentBuilder field(String name, long value) throws IOException { 387 | field(name); 388 | generator.writeNumber(value); 389 | return this; 390 | } 391 | 392 | public XmlXContentBuilder field(XContentBuilderString name, long value) throws IOException { 393 | field(name); 394 | generator.writeNumber(value); 395 | return this; 396 | } 397 | 398 | public XmlXContentBuilder field(String name, Float value) throws IOException { 399 | field(name); 400 | if (value == null) { 401 | generator.writeNull(); 402 | } else { 403 | generator.writeNumber(value.floatValue()); 404 | } 405 | return this; 406 | } 407 | 408 | public XmlXContentBuilder field(XContentBuilderString name, Float value) throws IOException { 409 | field(name); 410 | if (value == null) { 411 | generator.writeNull(); 412 | } else { 413 | generator.writeNumber(value.floatValue()); 414 | } 415 | return this; 416 | } 417 | 418 | public XmlXContentBuilder field(String name, float value) throws IOException { 419 | field(name); 420 | generator.writeNumber(value); 421 | return this; 422 | } 423 | 424 | public XmlXContentBuilder field(XContentBuilderString name, float value) throws IOException { 425 | field(name); 426 | generator.writeNumber(value); 427 | return this; 428 | } 429 | 430 | public XmlXContentBuilder field(String name, Double value) throws IOException { 431 | field(name); 432 | if (value == null) { 433 | generator.writeNull(); 434 | } else { 435 | generator.writeNumber(value); 436 | } 437 | return this; 438 | } 439 | 440 | public XmlXContentBuilder field(XContentBuilderString name, Double value) throws IOException { 441 | field(name); 442 | if (value == null) { 443 | generator.writeNull(); 444 | } else { 445 | generator.writeNumber(value); 446 | } 447 | return this; 448 | } 449 | 450 | public XmlXContentBuilder field(String name, double value) throws IOException { 451 | field(name); 452 | generator.writeNumber(value); 453 | return this; 454 | } 455 | 456 | public XmlXContentBuilder field(XContentBuilderString name, double value) throws IOException { 457 | field(name); 458 | generator.writeNumber(value); 459 | return this; 460 | } 461 | 462 | public XmlXContentBuilder field(String name, BigDecimal value) throws IOException { 463 | return field(name, value, value.scale(), RoundingMode.HALF_UP, true); 464 | } 465 | 466 | public XmlXContentBuilder field(XContentBuilderString name, BigDecimal value) throws IOException { 467 | return field(name, value, value.scale(), RoundingMode.HALF_UP, true); 468 | } 469 | 470 | public XmlXContentBuilder field(String name, BigDecimal value, int scale, RoundingMode rounding, boolean toDouble) throws IOException { 471 | field(name); 472 | if (toDouble) { 473 | try { 474 | generator.writeNumber(value.setScale(scale, rounding).doubleValue()); 475 | } catch (ArithmeticException e) { 476 | generator.writeString(value.toEngineeringString()); 477 | } 478 | } else { 479 | generator.writeString(value.toEngineeringString()); 480 | } 481 | return this; 482 | } 483 | 484 | public XmlXContentBuilder field(XContentBuilderString name, BigDecimal value, int scale, RoundingMode rounding, boolean toDouble) throws IOException { 485 | field(name); 486 | if (toDouble) { 487 | try { 488 | generator.writeNumber(value.setScale(scale, rounding).doubleValue()); 489 | } catch (ArithmeticException e) { 490 | generator.writeString(value.toEngineeringString()); 491 | } 492 | } else { 493 | generator.writeString(value.toEngineeringString()); 494 | } 495 | return this; 496 | } 497 | 498 | public XmlXContentBuilder field(String name, BytesReference value) throws IOException { 499 | field(name); 500 | if (!value.hasArray()) { 501 | value = value.toBytesArray(); 502 | } 503 | generator.writeBinary(value.array(), value.arrayOffset(), value.length()); 504 | return this; 505 | } 506 | 507 | public XmlXContentBuilder field(XContentBuilderString name, BytesReference value) throws IOException { 508 | field(name); 509 | if (!value.hasArray()) { 510 | value = value.toBytesArray(); 511 | } 512 | generator.writeBinary(value.array(), value.arrayOffset(), value.length()); 513 | return this; 514 | } 515 | 516 | public XmlXContentBuilder field(XContentBuilderString name, BytesRef value) throws IOException { 517 | field(name); 518 | generator.writeUTF8String(value.bytes, value.offset, value.length); 519 | return this; 520 | } 521 | 522 | public XmlXContentBuilder field(String name, Text value) throws IOException { 523 | field(name); 524 | if (value.hasBytes() && value.bytes().hasArray()) { 525 | generator.writeUTF8String(value.bytes().array(), value.bytes().arrayOffset(), value.bytes().length()); 526 | return this; 527 | } 528 | if (value.hasString()) { 529 | generator.writeString(value.string()); 530 | return this; 531 | } 532 | // TODO: TextBytesOptimization we can use a buffer here to convert it? maybe add a request to jackson to support InputStream as well? 533 | BytesArray bytesArray = value.bytes().toBytesArray(); 534 | generator.writeUTF8String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length()); 535 | return this; 536 | } 537 | 538 | public XmlXContentBuilder field(XContentBuilderString name, Text value) throws IOException { 539 | field(name); 540 | if (value.hasBytes() && value.bytes().hasArray()) { 541 | generator.writeUTF8String(value.bytes().array(), value.bytes().arrayOffset(), value.bytes().length()); 542 | return this; 543 | } 544 | if (value.hasString()) { 545 | generator.writeString(value.string()); 546 | return this; 547 | } 548 | // TODO: TextBytesOptimization we can use a buffer here to convert it? maybe add a request to jackson to support InputStream as well? 549 | BytesArray bytesArray = value.bytes().toBytesArray(); 550 | generator.writeUTF8String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length()); 551 | return this; 552 | } 553 | 554 | public XmlXContentBuilder field(String name, byte[] value, int offset, int length) throws IOException { 555 | field(name); 556 | generator.writeBinary(value, offset, length); 557 | return this; 558 | } 559 | 560 | public XmlXContentBuilder field(String name, Map value) throws IOException { 561 | field(name); 562 | value(value); 563 | return this; 564 | } 565 | 566 | public XmlXContentBuilder field(XContentBuilderString name, Map value) throws IOException { 567 | field(name); 568 | value(value); 569 | return this; 570 | } 571 | 572 | public XmlXContentBuilder field(String name, Iterable value) throws IOException { 573 | startArray(name); 574 | for (Object o : value) { 575 | value(o); 576 | } 577 | endArray(); 578 | return this; 579 | } 580 | 581 | public XmlXContentBuilder field(XContentBuilderString name, Iterable value) throws IOException { 582 | startArray(name); 583 | for (Object o : value) { 584 | value(o); 585 | } 586 | endArray(); 587 | return this; 588 | } 589 | 590 | public XmlXContentBuilder field(String name, String... value) throws IOException { 591 | startArray(name); 592 | for (String o : value) { 593 | value(o); 594 | } 595 | endArray(); 596 | return this; 597 | } 598 | 599 | 600 | public XmlXContentBuilder field(XContentBuilderString name, String... value) throws IOException { 601 | startArray(name); 602 | for (String o : value) { 603 | value(o); 604 | } 605 | endArray(); 606 | return this; 607 | } 608 | 609 | public XmlXContentBuilder field(String name, Object... value) throws IOException { 610 | startArray(name); 611 | for (Object o : value) { 612 | value(o); 613 | } 614 | endArray(); 615 | return this; 616 | } 617 | 618 | public XmlXContentBuilder field(XContentBuilderString name, Object... value) throws IOException { 619 | startArray(name); 620 | for (Object o : value) { 621 | value(o); 622 | } 623 | endArray(); 624 | return this; 625 | } 626 | 627 | public XmlXContentBuilder field(String name, int... value) throws IOException { 628 | startArray(name); 629 | for (Object o : value) { 630 | value(o); 631 | } 632 | endArray(); 633 | return this; 634 | } 635 | 636 | public XmlXContentBuilder field(XContentBuilderString name, int offset, int length, int... value) throws IOException { 637 | assert ((offset >= 0) && (value.length > length)); 638 | startArray(name); 639 | for (int i = offset; i < length; i++) { 640 | value(value[i]); 641 | } 642 | endArray(); 643 | return this; 644 | } 645 | 646 | public XmlXContentBuilder field(XContentBuilderString name, int... value) throws IOException { 647 | startArray(name); 648 | for (Object o : value) { 649 | value(o); 650 | } 651 | endArray(); 652 | return this; 653 | } 654 | 655 | public XmlXContentBuilder field(String name, long... value) throws IOException { 656 | startArray(name); 657 | for (Object o : value) { 658 | value(o); 659 | } 660 | endArray(); 661 | return this; 662 | } 663 | 664 | public XmlXContentBuilder field(XContentBuilderString name, long... value) throws IOException { 665 | startArray(name); 666 | for (Object o : value) { 667 | value(o); 668 | } 669 | endArray(); 670 | return this; 671 | } 672 | 673 | public XmlXContentBuilder field(String name, float... value) throws IOException { 674 | startArray(name); 675 | for (Object o : value) { 676 | value(o); 677 | } 678 | endArray(); 679 | return this; 680 | } 681 | 682 | public XmlXContentBuilder field(XContentBuilderString name, float... value) throws IOException { 683 | startArray(name); 684 | for (Object o : value) { 685 | value(o); 686 | } 687 | endArray(); 688 | return this; 689 | } 690 | 691 | public XmlXContentBuilder field(String name, double... value) throws IOException { 692 | startArray(name); 693 | for (Object o : value) { 694 | value(o); 695 | } 696 | endArray(); 697 | return this; 698 | } 699 | 700 | public XmlXContentBuilder field(XContentBuilderString name, double... value) throws IOException { 701 | startArray(name); 702 | for (Object o : value) { 703 | value(o); 704 | } 705 | endArray(); 706 | return this; 707 | } 708 | 709 | public XmlXContentBuilder field(String name, Object value) throws IOException { 710 | field(name); 711 | writeValue(value); 712 | return this; 713 | } 714 | 715 | public XmlXContentBuilder field(XContentBuilderString name, Object value) throws IOException { 716 | field(name); 717 | writeValue(value); 718 | return this; 719 | } 720 | 721 | public XmlXContentBuilder value(Object value) throws IOException { 722 | writeValue(value); 723 | return this; 724 | } 725 | 726 | public XmlXContentBuilder field(String name, boolean value) throws IOException { 727 | field(name); 728 | generator.writeBoolean(value); 729 | return this; 730 | } 731 | 732 | public XmlXContentBuilder field(XContentBuilderString name, boolean value) throws IOException { 733 | field(name); 734 | generator.writeBoolean(value); 735 | return this; 736 | } 737 | 738 | public XmlXContentBuilder field(String name, byte[] value) throws IOException { 739 | field(name); 740 | if (value == null) { 741 | generator.writeNull(); 742 | } else { 743 | generator.writeBinary(value); 744 | } 745 | return this; 746 | } 747 | 748 | public XmlXContentBuilder field(XContentBuilderString name, byte[] value) throws IOException { 749 | field(name); 750 | return value(value); 751 | } 752 | 753 | public XmlXContentBuilder field(String name, ReadableInstant date) throws IOException { 754 | field(name); 755 | return value(date); 756 | } 757 | 758 | public XmlXContentBuilder field(XContentBuilderString name, ReadableInstant date) throws IOException { 759 | field(name); 760 | return value(date); 761 | } 762 | 763 | public XmlXContentBuilder field(String name, ReadableInstant date, DateTimeFormatter formatter) throws IOException { 764 | field(name); 765 | return value(date, formatter); 766 | } 767 | 768 | public XmlXContentBuilder field(XContentBuilderString name, ReadableInstant date, DateTimeFormatter formatter) throws IOException { 769 | field(name); 770 | return value(date, formatter); 771 | } 772 | 773 | public XmlXContentBuilder field(String name, Date date) throws IOException { 774 | field(name); 775 | return value(date); 776 | } 777 | 778 | public XmlXContentBuilder field(XContentBuilderString name, Date date) throws IOException { 779 | field(name); 780 | return value(date); 781 | } 782 | 783 | public XmlXContentBuilder field(String name, Date date, DateTimeFormatter formatter) throws IOException { 784 | field(name); 785 | return value(date, formatter); 786 | } 787 | 788 | public XmlXContentBuilder field(XContentBuilderString name, Date date, DateTimeFormatter formatter) throws IOException { 789 | field(name); 790 | return value(date, formatter); 791 | } 792 | 793 | public XmlXContentBuilder nullField(String name) throws IOException { 794 | generator.writeNullField(name); 795 | return this; 796 | } 797 | 798 | public XmlXContentBuilder nullField(XContentBuilderString name) throws IOException { 799 | field(name); 800 | generator.writeNull(); 801 | return this; 802 | } 803 | 804 | public XmlXContentBuilder nullValue() throws IOException { 805 | generator.writeNull(); 806 | return this; 807 | } 808 | 809 | public XmlXContentBuilder timeValueField(XContentBuilderString rawFieldName, XContentBuilderString readableFieldName, TimeValue timeValue) throws IOException { 810 | if (humanReadable) { 811 | field(readableFieldName, timeValue.toString()); 812 | } 813 | field(rawFieldName, timeValue.millis()); 814 | return this; 815 | } 816 | 817 | public XmlXContentBuilder timeValueField(XContentBuilderString rawFieldName, XContentBuilderString readableFieldName, long rawTime) throws IOException { 818 | if (humanReadable) { 819 | field(readableFieldName, new TimeValue(rawTime).toString()); 820 | } 821 | field(rawFieldName, rawTime); 822 | return this; 823 | } 824 | 825 | public XmlXContentBuilder byteSizeField(XContentBuilderString rawFieldName, XContentBuilderString readableFieldName, ByteSizeValue byteSizeValue) throws IOException { 826 | if (humanReadable) { 827 | field(readableFieldName, byteSizeValue.toString()); 828 | } 829 | field(rawFieldName, byteSizeValue.bytes()); 830 | return this; 831 | } 832 | 833 | public XmlXContentBuilder byteSizeField(XContentBuilderString rawFieldName, XContentBuilderString readableFieldName, long rawSize) throws IOException { 834 | if (humanReadable) { 835 | field(readableFieldName, new ByteSizeValue(rawSize).toString()); 836 | } 837 | field(rawFieldName, rawSize); 838 | return this; 839 | } 840 | 841 | public XmlXContentBuilder value(Boolean value) throws IOException { 842 | if (value == null) { 843 | return nullValue(); 844 | } 845 | return value(value.booleanValue()); 846 | } 847 | 848 | public XmlXContentBuilder value(boolean value) throws IOException { 849 | generator.writeBoolean(value); 850 | return this; 851 | } 852 | 853 | public XmlXContentBuilder value(ReadableInstant date) throws IOException { 854 | return value(date, defaultDatePrinter); 855 | } 856 | 857 | public XmlXContentBuilder value(ReadableInstant date, DateTimeFormatter dateTimeFormatter) throws IOException { 858 | if (date == null) { 859 | return nullValue(); 860 | } 861 | return value(dateTimeFormatter.print(date)); 862 | } 863 | 864 | public XmlXContentBuilder value(Date date) throws IOException { 865 | return value(date, defaultDatePrinter); 866 | } 867 | 868 | public XmlXContentBuilder value(Date date, DateTimeFormatter dateTimeFormatter) throws IOException { 869 | if (date == null) { 870 | return nullValue(); 871 | } 872 | return value(dateTimeFormatter.print(date.getTime())); 873 | } 874 | 875 | public XmlXContentBuilder value(Integer value) throws IOException { 876 | if (value == null) { 877 | return nullValue(); 878 | } 879 | return value(value.intValue()); 880 | } 881 | 882 | public XmlXContentBuilder value(int value) throws IOException { 883 | generator.writeNumber(value); 884 | return this; 885 | } 886 | 887 | public XmlXContentBuilder value(Long value) throws IOException { 888 | if (value == null) { 889 | return nullValue(); 890 | } 891 | return value(value.longValue()); 892 | } 893 | 894 | public XmlXContentBuilder value(long value) throws IOException { 895 | generator.writeNumber(value); 896 | return this; 897 | } 898 | 899 | public XmlXContentBuilder value(Float value) throws IOException { 900 | if (value == null) { 901 | return nullValue(); 902 | } 903 | return value(value.floatValue()); 904 | } 905 | 906 | public XmlXContentBuilder value(float value) throws IOException { 907 | generator.writeNumber(value); 908 | return this; 909 | } 910 | 911 | public XmlXContentBuilder value(Double value) throws IOException { 912 | if (value == null) { 913 | return nullValue(); 914 | } 915 | return value(value.doubleValue()); 916 | } 917 | 918 | public XmlXContentBuilder value(double value) throws IOException { 919 | generator.writeNumber(value); 920 | return this; 921 | } 922 | 923 | public XmlXContentBuilder value(String value) throws IOException { 924 | if (value == null) { 925 | return nullValue(); 926 | } 927 | generator.writeString(value); 928 | return this; 929 | } 930 | 931 | public XmlXContentBuilder value(byte[] value) throws IOException { 932 | if (value == null) { 933 | return nullValue(); 934 | } 935 | generator.writeBinary(value); 936 | return this; 937 | } 938 | 939 | public XmlXContentBuilder value(byte[] value, int offset, int length) throws IOException { 940 | if (value == null) { 941 | return nullValue(); 942 | } 943 | generator.writeBinary(value, offset, length); 944 | return this; 945 | } 946 | 947 | public XmlXContentBuilder value(BytesReference value) throws IOException { 948 | if (value == null) { 949 | return nullValue(); 950 | } 951 | if (!value.hasArray()) { 952 | value = value.toBytesArray(); 953 | } 954 | generator.writeBinary(value.array(), value.arrayOffset(), value.length()); 955 | return this; 956 | } 957 | 958 | public XmlXContentBuilder value(Text value) throws IOException { 959 | if (value == null) { 960 | return nullValue(); 961 | } 962 | if (value.hasBytes() && value.bytes().hasArray()) { 963 | generator.writeUTF8String(value.bytes().array(), value.bytes().arrayOffset(), value.bytes().length()); 964 | return this; 965 | } 966 | if (value.hasString()) { 967 | generator.writeString(value.string()); 968 | return this; 969 | } 970 | BytesArray bytesArray = value.bytes().toBytesArray(); 971 | generator.writeUTF8String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length()); 972 | return this; 973 | } 974 | 975 | public XmlXContentBuilder map(Map map) throws IOException { 976 | if (map == null) { 977 | return nullValue(); 978 | } 979 | writeMap(map); 980 | return this; 981 | } 982 | 983 | public XmlXContentBuilder value(Map map) throws IOException { 984 | if (map == null) { 985 | return nullValue(); 986 | } 987 | writeMap(map); 988 | return this; 989 | } 990 | 991 | public XmlXContentBuilder value(Iterable value) throws IOException { 992 | if (value == null) { 993 | return nullValue(); 994 | } 995 | startArray(); 996 | for (Object o : value) { 997 | value(o); 998 | } 999 | endArray(); 1000 | return this; 1001 | } 1002 | 1003 | public XmlXContentBuilder copyCurrentStructure(XContentParser parser) throws IOException { 1004 | generator.copyCurrentStructure(parser); 1005 | return this; 1006 | } 1007 | 1008 | public XmlXContentBuilder flush() throws IOException { 1009 | generator.flush(); 1010 | return this; 1011 | } 1012 | 1013 | public void close() { 1014 | try { 1015 | generator.close(); 1016 | } catch (IOException e) { 1017 | // ignore 1018 | } 1019 | } 1020 | 1021 | public XContentGenerator generator() { 1022 | return this.generator; 1023 | } 1024 | 1025 | public OutputStream stream() { 1026 | return this.bos; 1027 | } 1028 | 1029 | @Override 1030 | public BytesReference bytes() { 1031 | close(); 1032 | return ((BytesStream) bos).bytes(); 1033 | } 1034 | 1035 | /** 1036 | * Returns the actual stream used. 1037 | */ 1038 | public BytesStream bytesStream() throws IOException { 1039 | close(); 1040 | return (BytesStream) bos; 1041 | } 1042 | 1043 | /** 1044 | * Returns a string representation of the builder (only applicable for text based xcontent). 1045 | */ 1046 | public String string() throws IOException { 1047 | close(); 1048 | BytesArray bytesArray = bytes().toBytesArray(); 1049 | return new String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length(), Charsets.UTF_8); 1050 | } 1051 | 1052 | private void writeMap(Map map) throws IOException { 1053 | generator.writeStartObject(); 1054 | 1055 | for (Map.Entry entry : map.entrySet()) { 1056 | field(entry.getKey()); 1057 | Object value = entry.getValue(); 1058 | if (value == null) { 1059 | generator.writeNull(); 1060 | } else { 1061 | writeValue(value); 1062 | } 1063 | } 1064 | generator.writeEndObject(); 1065 | } 1066 | 1067 | @SuppressWarnings("unchecked") 1068 | private void writeValue(Object value) throws IOException { 1069 | if (value == null) { 1070 | generator.writeNull(); 1071 | return; 1072 | } 1073 | Class type = value.getClass(); 1074 | if (type == String.class) { 1075 | generator.writeString((String) value); 1076 | } else if (type == Integer.class) { 1077 | generator.writeNumber(((Integer) value).intValue()); 1078 | } else if (type == Long.class) { 1079 | generator.writeNumber(((Long) value).longValue()); 1080 | } else if (type == Float.class) { 1081 | generator.writeNumber(((Float) value).floatValue()); 1082 | } else if (type == Double.class) { 1083 | generator.writeNumber(((Double) value).doubleValue()); 1084 | } else if (type == Short.class) { 1085 | generator.writeNumber(((Short) value).shortValue()); 1086 | } else if (type == Boolean.class) { 1087 | generator.writeBoolean(((Boolean) value).booleanValue()); 1088 | } else if (type == GeoPoint.class) { 1089 | generator.writeStartObject(); 1090 | generator.writeNumberField("lat", ((GeoPoint) value).lat()); 1091 | generator.writeNumberField("lon", ((GeoPoint) value).lon()); 1092 | generator.writeEndObject(); 1093 | } else if (value instanceof Map) { 1094 | writeMap((Map) value); 1095 | } else if (value instanceof Iterable) { 1096 | generator.writeStartArray(); 1097 | for (Object v : (Iterable) value) { 1098 | writeValue(v); 1099 | } 1100 | generator.writeEndArray(); 1101 | } else if (value instanceof Object[]) { 1102 | generator.writeStartArray(); 1103 | for (Object v : (Object[]) value) { 1104 | writeValue(v); 1105 | } 1106 | generator.writeEndArray(); 1107 | } else if (type == byte[].class) { 1108 | generator.writeBinary((byte[]) value); 1109 | } else if (value instanceof Date) { 1110 | generator.writeString(XmlXContentBuilder.defaultDatePrinter.print(((Date) value).getTime())); 1111 | } else if (value instanceof Calendar) { 1112 | generator.writeString(XmlXContentBuilder.defaultDatePrinter.print((((Calendar) value)).getTimeInMillis())); 1113 | } else if (value instanceof ReadableInstant) { 1114 | generator.writeString(XmlXContentBuilder.defaultDatePrinter.print((((ReadableInstant) value)).getMillis())); 1115 | } else if (value instanceof BytesReference) { 1116 | BytesReference bytes = (BytesReference) value; 1117 | if (!bytes.hasArray()) { 1118 | bytes = bytes.toBytesArray(); 1119 | } 1120 | generator.writeBinary(bytes.array(), bytes.arrayOffset(), bytes.length()); 1121 | } else if (value instanceof Text) { 1122 | Text text = (Text) value; 1123 | if (text.hasBytes() && text.bytes().hasArray()) { 1124 | generator.writeUTF8String(text.bytes().array(), text.bytes().arrayOffset(), text.bytes().length()); 1125 | } else if (text.hasString()) { 1126 | generator.writeString(text.string()); 1127 | } else { 1128 | BytesArray bytesArray = text.bytes().toBytesArray(); 1129 | generator.writeUTF8String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length()); 1130 | } 1131 | //} else if (value instanceof ToXContent) { 1132 | // ((ToXContent) value).toXContent(this, ToXContent.EMPTY_PARAMS); 1133 | } else if (value instanceof double[]) { 1134 | generator.writeStartArray(); 1135 | for (double v : (double[]) value) { 1136 | generator.writeNumber(v); 1137 | } 1138 | generator.writeEndArray(); 1139 | } else if (value instanceof long[]) { 1140 | generator.writeStartArray(); 1141 | for (long v : (long[]) value) { 1142 | generator.writeNumber(v); 1143 | } 1144 | generator.writeEndArray(); 1145 | } else if (value instanceof int[]) { 1146 | generator.writeStartArray(); 1147 | for (int v : (int[]) value) { 1148 | generator.writeNumber(v); 1149 | } 1150 | generator.writeEndArray(); 1151 | } else if (value instanceof float[]) { 1152 | generator.writeStartArray(); 1153 | for (float v : (float[]) value) { 1154 | generator.writeNumber(v); 1155 | } 1156 | generator.writeEndArray(); 1157 | } else if (value instanceof short[]) { 1158 | generator.writeStartArray(); 1159 | for (float v : (short[]) value) { 1160 | generator.writeNumber(v); 1161 | } 1162 | generator.writeEndArray(); 1163 | } else { 1164 | // if this is a "value" object, like enum, DistanceUnit, ..., just toString it 1165 | // yea, it can be misleading when toString a Java class, but really, jackson should be used in that case 1166 | generator.writeString(value.toString()); 1167 | //throw new ElasticsearchIllegalArgumentException("type not supported for generic value conversion: " + type); 1168 | } 1169 | } 1170 | } 1171 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/XmlXContentFactory.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.common.xcontent; 2 | 3 | import com.fasterxml.jackson.dataformat.smile.SmileConstants; 4 | import org.elasticsearch.ElasticsearchParseException; 5 | import org.elasticsearch.common.bytes.BytesArray; 6 | import org.elasticsearch.common.bytes.BytesReference; 7 | import org.elasticsearch.common.xcontent.XContent; 8 | import org.elasticsearch.common.xcontent.json.JsonXContent; 9 | import org.elasticsearch.common.xcontent.smile.SmileXContent; 10 | import org.elasticsearch.common.xcontent.yaml.YamlXContent; 11 | 12 | import org.xbib.elasticsearch.common.xcontent.xml.XmlXContent; 13 | import org.xbib.elasticsearch.common.xcontent.xml.XmlXParams; 14 | 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.io.OutputStream; 18 | import java.util.Arrays; 19 | 20 | /** 21 | * A one stop to use {@link org.elasticsearch.common.xcontent.XContent} and {@link XmlXContentBuilder}. 22 | */ 23 | public class XmlXContentFactory { 24 | 25 | private static int GUESS_HEADER_LENGTH = 20; 26 | 27 | /** 28 | * Returns a content builder using JSON format ({@link XmlXContentType#JSON}. 29 | */ 30 | public static XmlXContentBuilder jsonBuilder() throws IOException { 31 | return contentBuilder(XmlXContentType.JSON); 32 | } 33 | 34 | /** 35 | * Constructs a new json builder that will output the result into the provided output stream. 36 | */ 37 | public static XmlXContentBuilder jsonBuilder(OutputStream os) throws IOException { 38 | return new XmlXContentBuilder(JsonXContent.jsonXContent, os); 39 | } 40 | 41 | /** 42 | * Returns a content builder using SMILE format ({@link XmlXContentType#SMILE}. 43 | */ 44 | public static XmlXContentBuilder smileBuilder() throws IOException { 45 | return contentBuilder(XmlXContentType.SMILE); 46 | } 47 | 48 | /** 49 | * Constructs a new json builder that will output the result into the provided output stream. 50 | */ 51 | public static XmlXContentBuilder smileBuilder(OutputStream os) throws IOException { 52 | return new XmlXContentBuilder(SmileXContent.smileXContent, os); 53 | } 54 | 55 | /** 56 | * Constructs a new yaml builder that will output the result into the provided output stream. 57 | */ 58 | public static XmlXContentBuilder yamlBuilder(OutputStream os) throws IOException { 59 | return new XmlXContentBuilder(YamlXContent.yamlXContent, os); 60 | } 61 | 62 | /** 63 | * Constructs a new xml builder using XML. 64 | */ 65 | public static XmlXContentBuilder xmlBuilder() throws IOException { 66 | XmlXParams params = new XmlXParams(); 67 | return XmlXContent.contentBuilder(params); 68 | } 69 | 70 | /** 71 | * Constructs a new xml builder using XML. 72 | */ 73 | public static XmlXContentBuilder xmlBuilder(XmlXParams params) throws IOException { 74 | return XmlXContent.contentBuilder(params); 75 | } 76 | 77 | /** 78 | * Constructs a new xml builder that will output the result into the provided output stream. 79 | */ 80 | public static XmlXContentBuilder xmlBuilder(OutputStream os) throws IOException { 81 | return new XmlXContentBuilder(XmlXContent.xmlXContent(), os); 82 | } 83 | 84 | /** 85 | * Constructs a xcontent builder that will output the result into the provided output stream. 86 | */ 87 | public static XmlXContentBuilder contentBuilder(XmlXContentType type, OutputStream outputStream) throws IOException { 88 | if (type == XmlXContentType.JSON) { 89 | return jsonBuilder(outputStream); 90 | } else if (type == XmlXContentType.SMILE) { 91 | return smileBuilder(outputStream); 92 | } else if (type == XmlXContentType.YAML) { 93 | return yamlBuilder(outputStream); 94 | } else if (type == XmlXContentType.XML) { 95 | return xmlBuilder(outputStream); 96 | } 97 | throw new IllegalArgumentException("No matching content type for " + type); 98 | } 99 | 100 | /** 101 | * Returns a binary content builder for the provided content type. 102 | */ 103 | public static XmlXContentBuilder contentBuilder(XmlXContentType type) throws IOException { 104 | if (type == XmlXContentType.XML) { 105 | XmlXParams params = new XmlXParams(); 106 | return XmlXContent.contentBuilder(params); 107 | } 108 | throw new IllegalArgumentException("No matching content type for " + type); 109 | } 110 | 111 | /** 112 | * Returns the {@link org.elasticsearch.common.xcontent.XContent} for the provided content type. 113 | */ 114 | public static XContent xContent(XmlXContentType type) { 115 | return type.xContent(); 116 | } 117 | 118 | /** 119 | * Guesses the content type based on the provided char sequence. 120 | */ 121 | public static XmlXContentType xContentType(CharSequence content) { 122 | int length = content.length() < GUESS_HEADER_LENGTH ? content.length() : GUESS_HEADER_LENGTH; 123 | if (length == 0) { 124 | return null; 125 | } 126 | char first = content.charAt(0); 127 | if (first == '{') { 128 | return XmlXContentType.JSON; 129 | } 130 | // Should we throw a failure here? Smile idea is to use it in bytes.... 131 | if (length > 2 && first == SmileConstants.HEADER_BYTE_1 && content.charAt(1) == SmileConstants.HEADER_BYTE_2 && content.charAt(2) == SmileConstants.HEADER_BYTE_3) { 132 | return XmlXContentType.SMILE; 133 | } 134 | if (length > 2 && first == '-' && content.charAt(1) == '-' && content.charAt(2) == '-') { 135 | return XmlXContentType.YAML; 136 | } 137 | for (int i = 0; i < length; i++) { 138 | char c = content.charAt(i); 139 | if (c == '{') { 140 | return XmlXContentType.JSON; 141 | } 142 | if (c == '<') { 143 | return XmlXContentType.XML; 144 | } 145 | } 146 | return null; 147 | } 148 | 149 | /** 150 | * Guesses the content (type) based on the provided char sequence. 151 | */ 152 | public static XContent xContent(CharSequence content) { 153 | XmlXContentType type = xContentType(content); 154 | if (type == null) { 155 | throw new ElasticsearchParseException("Failed to derive xcontent from " + content); 156 | } 157 | return xContent(type); 158 | } 159 | 160 | /** 161 | * Guesses the content type based on the provided bytes. 162 | */ 163 | public static XContent xContent(byte[] data) { 164 | return xContent(data, 0, data.length); 165 | } 166 | 167 | /** 168 | * Guesses the content type based on the provided bytes. 169 | */ 170 | public static XContent xContent(byte[] data, int offset, int length) { 171 | XmlXContentType type = xContentType(data, offset, length); 172 | if (type == null) { 173 | throw new ElasticsearchParseException("Failed to derive xcontent from (offset=" + offset + ", length=" + length + "): " + Arrays.toString(data)); 174 | } 175 | return xContent(type); 176 | } 177 | 178 | /** 179 | * Guesses the content type based on the provided bytes. 180 | */ 181 | public static XmlXContentType xContentType(byte[] data) { 182 | return xContentType(data, 0, data.length); 183 | } 184 | 185 | /** 186 | * Guesses the content type based on the provided input stream. 187 | */ 188 | public static XmlXContentType xContentType(InputStream si) throws IOException { 189 | int first = si.read(); 190 | if (first == -1) { 191 | return null; 192 | } 193 | int second = si.read(); 194 | if (second == -1) { 195 | return null; 196 | } 197 | if (first == SmileConstants.HEADER_BYTE_1 && second == SmileConstants.HEADER_BYTE_2) { 198 | int third = si.read(); 199 | if (third == SmileConstants.HEADER_BYTE_3) { 200 | return XmlXContentType.SMILE; 201 | } 202 | } 203 | if (first == '{' || second == '{') { 204 | return XmlXContentType.JSON; 205 | } 206 | if (first == '-' && second == '-') { 207 | int third = si.read(); 208 | if (third == '-') { 209 | return XmlXContentType.YAML; 210 | } 211 | } 212 | if (first == '<' && second == '?') { 213 | int third = si.read(); 214 | if (third == 'x') { 215 | return XmlXContentType.XML; 216 | } 217 | } 218 | for (int i = 2; i < GUESS_HEADER_LENGTH; i++) { 219 | int val = si.read(); 220 | if (val == -1) { 221 | return null; 222 | } 223 | if (val == '{') { 224 | return XmlXContentType.JSON; 225 | } 226 | } 227 | return null; 228 | } 229 | 230 | /** 231 | * Guesses the content type based on the provided bytes. 232 | */ 233 | public static XmlXContentType xContentType(byte[] data, int offset, int length) { 234 | return xContentType(new BytesArray(data, offset, length)); 235 | } 236 | 237 | public static XContent xContent(BytesReference bytes) { 238 | XmlXContentType type = xContentType(bytes); 239 | if (type == null) { 240 | throw new ElasticsearchParseException("Failed to derive xcontent from " + bytes); 241 | } 242 | return xContent(type); 243 | } 244 | 245 | /** 246 | * Guesses the content type based on the provided bytes. 247 | */ 248 | public static XmlXContentType xContentType(BytesReference bytes) { 249 | int length = bytes.length() < GUESS_HEADER_LENGTH ? bytes.length() : GUESS_HEADER_LENGTH; 250 | if (length == 0) { 251 | return null; 252 | } 253 | byte first = bytes.get(0); 254 | if (first == '{') { 255 | return XmlXContentType.JSON; 256 | } 257 | if (length > 2 && first == SmileConstants.HEADER_BYTE_1 && bytes.get(1) == SmileConstants.HEADER_BYTE_2 && bytes.get(2) == SmileConstants.HEADER_BYTE_3) { 258 | return XmlXContentType.SMILE; 259 | } 260 | if (length > 2 && first == '-' && bytes.get(1) == '-' && bytes.get(2) == '-') { 261 | return XmlXContentType.YAML; 262 | } 263 | if (length > 2 && first == '<' && bytes.get(1) == '?' && bytes.get(2) == 'x') { 264 | return XmlXContentType.XML; 265 | } 266 | for (int i = 0; i < length; i++) { 267 | if (bytes.get(i) == '{') { 268 | return XmlXContentType.JSON; 269 | } 270 | } 271 | return null; 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/XmlXContentType.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.common.xcontent; 2 | 3 | import org.elasticsearch.common.xcontent.XContent; 4 | import org.elasticsearch.common.xcontent.json.JsonXContent; 5 | import org.elasticsearch.common.xcontent.smile.SmileXContent; 6 | import org.elasticsearch.common.xcontent.yaml.YamlXContent; 7 | 8 | import org.xbib.elasticsearch.common.xcontent.xml.XmlXContent; 9 | 10 | /** 11 | * The content type of {@link org.elasticsearch.common.xcontent.XContent}. 12 | */ 13 | public enum XmlXContentType { 14 | 15 | /** 16 | * A JSON based content type. 17 | */ 18 | JSON(0) { 19 | @Override 20 | public String restContentType() { 21 | return "application/json; charset=UTF-8"; 22 | } 23 | 24 | @Override 25 | public String shortName() { 26 | return "json"; 27 | } 28 | 29 | @Override 30 | public XContent xContent() { 31 | return JsonXContent.jsonXContent; 32 | } 33 | }, 34 | /** 35 | * The jackson based smile binary format. Fast and compact binary format. 36 | */ 37 | SMILE(1) { 38 | @Override 39 | public String restContentType() { 40 | return "application/smile"; 41 | } 42 | 43 | @Override 44 | public String shortName() { 45 | return "smile"; 46 | } 47 | 48 | @Override 49 | public XContent xContent() { 50 | return SmileXContent.smileXContent; 51 | } 52 | }, 53 | /** 54 | * The YAML format. 55 | */ 56 | YAML(2) { 57 | @Override 58 | public String restContentType() { 59 | return "application/yaml"; 60 | } 61 | 62 | @Override 63 | public String shortName() { 64 | return "yaml"; 65 | } 66 | 67 | @Override 68 | public XContent xContent() { 69 | return YamlXContent.yamlXContent; 70 | } 71 | }, 72 | /** 73 | * The XML format. 74 | */ 75 | XML(3) { 76 | @Override 77 | public String restContentType() { 78 | return "application/xml"; 79 | } 80 | 81 | @Override 82 | public String shortName() { 83 | return "xml"; 84 | } 85 | 86 | @Override 87 | public XContent xContent() { 88 | return XmlXContent.xmlXContent(); 89 | } 90 | }; 91 | 92 | public static XmlXContentType fromRestContentType(String contentType) { 93 | if (contentType == null) { 94 | return null; 95 | } 96 | if ("application/json".equals(contentType) || "json".equalsIgnoreCase(contentType)) { 97 | return JSON; 98 | } 99 | if ("application/smile".equals(contentType) || "smile".equalsIgnoreCase(contentType)) { 100 | return SMILE; 101 | } 102 | if ("application/yaml".equals(contentType) || "yaml".equalsIgnoreCase(contentType)) { 103 | return YAML; 104 | } 105 | if ("application/xml".equals(contentType) || "xml".equalsIgnoreCase(contentType)) { 106 | return XML; 107 | } 108 | return null; 109 | } 110 | 111 | private int index; 112 | 113 | XmlXContentType(int index) { 114 | this.index = index; 115 | } 116 | 117 | public int index() { 118 | return index; 119 | } 120 | 121 | public abstract String restContentType(); 122 | 123 | public abstract String shortName(); 124 | 125 | public abstract XContent xContent(); 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/xml/ISO9075.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xbib.elasticsearch.common.xcontent.xml; 3 | 4 | public class ISO9075 { 5 | private static final int MASK = (1 << 4) - 1; 6 | 7 | private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 8 | 9 | private ISO9075() { 10 | } 11 | 12 | public static String encode(String toEncode) { 13 | if ((toEncode == null) || (toEncode.length() == 0)) { 14 | return toEncode; 15 | } else if (XML11Char.isXML11ValidName(toEncode) && (!toEncode.contains("_x"))) { 16 | return toEncode; 17 | } else { 18 | StringBuilder builder = new StringBuilder(toEncode.length()); 19 | for (int i = 0; i < toEncode.length(); i++) { 20 | char c = toEncode.charAt(i); 21 | if (i == 0) { 22 | if (XML11Char.isXML11NCNameStart(c)) { 23 | if (matchesEncodedPattern(toEncode, i)) { 24 | encode('_', builder); 25 | } else { 26 | builder.append(c); 27 | } 28 | } else { 29 | encode(c, builder); 30 | } 31 | } else if (!XML11Char.isXML11NCName(c)) { 32 | encode(c, builder); 33 | } else { 34 | if (matchesEncodedPattern(toEncode, i)) { 35 | encode('_', builder); 36 | } else { 37 | builder.append(c); 38 | } 39 | } 40 | } 41 | return builder.toString(); 42 | } 43 | } 44 | 45 | private static boolean matchesEncodedPattern(String string, int position) { 46 | return (string.length() >= position + 6) 47 | && (string.charAt(position) == '_') && (string.charAt(position + 1) == 'x') 48 | && isHexChar(string.charAt(position + 2)) && isHexChar(string.charAt(position + 3)) 49 | && isHexChar(string.charAt(position + 4)) && isHexChar(string.charAt(position + 5)) 50 | && (string.charAt(position + 6) == '_'); 51 | } 52 | 53 | private static boolean isHexChar(char c) { 54 | switch (c) { 55 | case '0': 56 | case '1': 57 | case '2': 58 | case '3': 59 | case '4': 60 | case '5': 61 | case '6': 62 | case '7': 63 | case '8': 64 | case '9': 65 | case 'a': 66 | case 'b': 67 | case 'c': 68 | case 'd': 69 | case 'e': 70 | case 'f': 71 | case 'A': 72 | case 'B': 73 | case 'C': 74 | case 'D': 75 | case 'E': 76 | case 'F': 77 | return true; 78 | default: 79 | return false; 80 | } 81 | } 82 | 83 | public static String decode(String toDecode) { 84 | if ((toDecode == null) || (toDecode.length() < 7) || (!toDecode.contains("_x"))) { 85 | return toDecode; 86 | } 87 | StringBuilder decoded = new StringBuilder(); 88 | for (int i = 0, l = toDecode.length(); i < l; i++) { 89 | if (matchesEncodedPattern(toDecode, i)) { 90 | decoded.append(((char) Integer.parseInt(toDecode.substring(i + 2, i + 6), 16))); 91 | i += 6; 92 | } else { 93 | decoded.append(toDecode.charAt(i)); 94 | } 95 | } 96 | return decoded.toString(); 97 | } 98 | 99 | private static void encode(char c, StringBuilder builder) { 100 | char[] buf = new char[]{'_', 'x', '0', '0', '0', '0', '_'}; 101 | int charPos = 6; 102 | do { 103 | buf[--charPos] = DIGITS[c & MASK]; 104 | c >>>= 4; 105 | } 106 | while (c != 0); 107 | builder.append(buf); 108 | } 109 | } -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/xml/XML11Char.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xbib.elasticsearch.common.xcontent.xml; 3 | 4 | import java.util.Arrays; 5 | 6 | /** 7 | * This class defines the basic properties of characters in XML 1.1. The data 8 | * in this class can be used to verify that a character is a valid 9 | * XML 1.1 character or if the character is a space, name start, or name 10 | * character. 11 | *

12 | * A series of convenience methods are supplied to ease the burden 13 | * of the developer. Using the character as an index into the XML11CHARS 14 | * array and applying the appropriate mask flag (e.g. 15 | * MASK_VALID), yields the same results as calling the 16 | * convenience methods. There is one exception: check the comments 17 | * for the isValid method for details. 18 | * 19 | * Taken from org.apache.xerces.util.XML11Char.java 20 | * 21 | */ 22 | public class XML11Char { 23 | 24 | /** Character flags for XML 1.1. */ 25 | private static final byte XML11CHARS [] = new byte [1 << 16]; 26 | 27 | /** XML 1.1 Valid character mask. */ 28 | public static final int MASK_XML11_VALID = 0x01; 29 | 30 | /** XML 1.1 Space character mask. */ 31 | public static final int MASK_XML11_SPACE = 0x02; 32 | 33 | /** XML 1.1 Name start character mask. */ 34 | public static final int MASK_XML11_NAME_START = 0x04; 35 | 36 | /** XML 1.1 Name character mask. */ 37 | public static final int MASK_XML11_NAME = 0x08; 38 | 39 | /** XML 1.1 control character mask */ 40 | public static final int MASK_XML11_CONTROL = 0x10; 41 | 42 | /** XML 1.1 content for external entities (valid - "special" chars - control chars) */ 43 | public static final int MASK_XML11_CONTENT = 0x20; 44 | 45 | /** XML namespaces 1.1 NCNameStart */ 46 | public static final int MASK_XML11_NCNAME_START = 0x40; 47 | 48 | /** XML namespaces 1.1 NCName */ 49 | public static final int MASK_XML11_NCNAME = 0x80; 50 | 51 | /** XML 1.1 content for internal entities (valid - "special" chars) */ 52 | public static final int MASK_XML11_CONTENT_INTERNAL = MASK_XML11_CONTROL | MASK_XML11_CONTENT; 53 | 54 | static { 55 | Arrays.fill(XML11CHARS, 1, 9, (byte) 17 ); // Fill 8 of value (byte) 17 56 | XML11CHARS[9] = 35; 57 | XML11CHARS[10] = 3; 58 | Arrays.fill(XML11CHARS, 11, 13, (byte) 17 ); // Fill 2 of value (byte) 17 59 | XML11CHARS[13] = 3; 60 | Arrays.fill(XML11CHARS, 14, 32, (byte) 17 ); // Fill 18 of value (byte) 17 61 | XML11CHARS[32] = 35; 62 | Arrays.fill(XML11CHARS, 33, 38, (byte) 33 ); // Fill 5 of value (byte) 33 63 | XML11CHARS[38] = 1; 64 | Arrays.fill(XML11CHARS, 39, 45, (byte) 33 ); // Fill 6 of value (byte) 33 65 | Arrays.fill(XML11CHARS, 45, 47, (byte) -87 ); // Fill 2 of value (byte) -87 66 | XML11CHARS[47] = 33; 67 | Arrays.fill(XML11CHARS, 48, 58, (byte) -87 ); // Fill 10 of value (byte) -87 68 | XML11CHARS[58] = 45; 69 | XML11CHARS[59] = 33; 70 | XML11CHARS[60] = 1; 71 | Arrays.fill(XML11CHARS, 61, 65, (byte) 33 ); // Fill 4 of value (byte) 33 72 | Arrays.fill(XML11CHARS, 65, 91, (byte) -19 ); // Fill 26 of value (byte) -19 73 | Arrays.fill(XML11CHARS, 91, 93, (byte) 33 ); // Fill 2 of value (byte) 33 74 | XML11CHARS[93] = 1; 75 | XML11CHARS[94] = 33; 76 | XML11CHARS[95] = -19; 77 | XML11CHARS[96] = 33; 78 | Arrays.fill(XML11CHARS, 97, 123, (byte) -19 ); // Fill 26 of value (byte) -19 79 | Arrays.fill(XML11CHARS, 123, 127, (byte) 33 ); // Fill 4 of value (byte) 33 80 | Arrays.fill(XML11CHARS, 127, 133, (byte) 17 ); // Fill 6 of value (byte) 17 81 | XML11CHARS[133] = 35; 82 | Arrays.fill(XML11CHARS, 134, 160, (byte) 17 ); // Fill 26 of value (byte) 17 83 | Arrays.fill(XML11CHARS, 160, 183, (byte) 33 ); // Fill 23 of value (byte) 33 84 | XML11CHARS[183] = -87; 85 | Arrays.fill(XML11CHARS, 184, 192, (byte) 33 ); // Fill 8 of value (byte) 33 86 | Arrays.fill(XML11CHARS, 192, 215, (byte) -19 ); // Fill 23 of value (byte) -19 87 | XML11CHARS[215] = 33; 88 | Arrays.fill(XML11CHARS, 216, 247, (byte) -19 ); // Fill 31 of value (byte) -19 89 | XML11CHARS[247] = 33; 90 | Arrays.fill(XML11CHARS, 248, 768, (byte) -19 ); // Fill 520 of value (byte) -19 91 | Arrays.fill(XML11CHARS, 768, 880, (byte) -87 ); // Fill 112 of value (byte) -87 92 | Arrays.fill(XML11CHARS, 880, 894, (byte) -19 ); // Fill 14 of value (byte) -19 93 | XML11CHARS[894] = 33; 94 | Arrays.fill(XML11CHARS, 895, 8192, (byte) -19 ); // Fill 7297 of value (byte) -19 95 | Arrays.fill(XML11CHARS, 8192, 8204, (byte) 33 ); // Fill 12 of value (byte) 33 96 | Arrays.fill(XML11CHARS, 8204, 8206, (byte) -19 ); // Fill 2 of value (byte) -19 97 | Arrays.fill(XML11CHARS, 8206, 8232, (byte) 33 ); // Fill 26 of value (byte) 33 98 | XML11CHARS[8232] = 35; 99 | Arrays.fill(XML11CHARS, 8233, 8255, (byte) 33 ); // Fill 22 of value (byte) 33 100 | Arrays.fill(XML11CHARS, 8255, 8257, (byte) -87 ); // Fill 2 of value (byte) -87 101 | Arrays.fill(XML11CHARS, 8257, 8304, (byte) 33 ); // Fill 47 of value (byte) 33 102 | Arrays.fill(XML11CHARS, 8304, 8592, (byte) -19 ); // Fill 288 of value (byte) -19 103 | Arrays.fill(XML11CHARS, 8592, 11264, (byte) 33 ); // Fill 2672 of value (byte) 33 104 | Arrays.fill(XML11CHARS, 11264, 12272, (byte) -19 ); // Fill 1008 of value (byte) -19 105 | Arrays.fill(XML11CHARS, 12272, 12289, (byte) 33 ); // Fill 17 of value (byte) 33 106 | Arrays.fill(XML11CHARS, 12289, 55296, (byte) -19 ); // Fill 43007 of value (byte) -19 107 | Arrays.fill(XML11CHARS, 57344, 63744, (byte) 33 ); // Fill 6400 of value (byte) 33 108 | Arrays.fill(XML11CHARS, 63744, 64976, (byte) -19 ); // Fill 1232 of value (byte) -19 109 | Arrays.fill(XML11CHARS, 64976, 65008, (byte) 33 ); // Fill 32 of value (byte) 33 110 | Arrays.fill(XML11CHARS, 65008, 65534, (byte) -19 ); // Fill 526 of value (byte) -19 111 | 112 | } 113 | 114 | /** 115 | * Returns true if the specified character is a space character 116 | * as amdended in the XML 1.1 specification. 117 | * 118 | * @param c The character to check. 119 | */ 120 | public static boolean isXML11Space(int c) { 121 | return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_SPACE) != 0); 122 | } 123 | 124 | /** 125 | * Returns true if the specified character is valid. This method 126 | * also checks the surrogate character range from 0x10000 to 0x10FFFF. 127 | *

128 | * If the program chooses to apply the mask directly to the 129 | * XML11CHARS array, then they are responsible for checking 130 | * the surrogate character range. 131 | * 132 | * @param c The character to check. 133 | */ 134 | public static boolean isXML11Valid(int c) { 135 | return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_VALID) != 0) 136 | || (0x10000 <= c && c <= 0x10FFFF); 137 | } 138 | 139 | /** 140 | * Returns true if the specified character is invalid. 141 | * 142 | * @param c The character to check. 143 | */ 144 | public static boolean isXML11Invalid(int c) { 145 | return !isXML11Valid(c); 146 | } 147 | 148 | /** 149 | * Returns true if the specified character is valid and permitted outside 150 | * of a character reference. 151 | * That is, this method will return false for the same set as 152 | * isXML11Valid, except it also reports false for "control characters". 153 | * 154 | * @param c The character to check. 155 | */ 156 | public static boolean isXML11ValidLiteral(int c) { 157 | return ((c < 0x10000 && ((XML11CHARS[c] & MASK_XML11_VALID) != 0 && (XML11CHARS[c] & MASK_XML11_CONTROL) == 0)) 158 | || (0x10000 <= c && c <= 0x10FFFF)); 159 | } 160 | 161 | /** 162 | * Returns true if the specified character can be considered 163 | * content in an external parsed entity. 164 | * 165 | * @param c The character to check. 166 | */ 167 | public static boolean isXML11Content(int c) { 168 | return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_CONTENT) != 0) || 169 | (0x10000 <= c && c <= 0x10FFFF); 170 | } 171 | 172 | /** 173 | * Returns true if the specified character can be considered 174 | * content in an internal parsed entity. 175 | * 176 | * @param c The character to check. 177 | */ 178 | public static boolean isXML11InternalEntityContent(int c) { 179 | return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_CONTENT_INTERNAL) != 0) || 180 | (0x10000 <= c && c <= 0x10FFFF); 181 | } 182 | 183 | /** 184 | * Returns true if the specified character is a valid name start 185 | * character as defined by production [4] in the XML 1.1 186 | * specification. 187 | * 188 | * @param c The character to check. 189 | */ 190 | public static boolean isXML11NameStart(int c) { 191 | return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_NAME_START) != 0) 192 | || (0x10000 <= c && c < 0xF0000); 193 | } 194 | 195 | /** 196 | * Returns true if the specified character is a valid name 197 | * character as defined by production [4a] in the XML 1.1 198 | * specification. 199 | * 200 | * @param c The character to check. 201 | */ 202 | public static boolean isXML11Name(int c) { 203 | return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_NAME) != 0) 204 | || (c >= 0x10000 && c < 0xF0000); 205 | } 206 | 207 | /** 208 | * Returns true if the specified character is a valid NCName start 209 | * character as defined by production [4] in Namespaces in XML 210 | * 1.1 recommendation. 211 | * 212 | * @param c The character to check. 213 | */ 214 | public static boolean isXML11NCNameStart(int c) { 215 | return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_NCNAME_START) != 0) 216 | || (0x10000 <= c && c < 0xF0000); 217 | } 218 | 219 | /** 220 | * Returns true if the specified character is a valid NCName 221 | * character as defined by production [5] in Namespaces in XML 222 | * 1.1 recommendation. 223 | * 224 | * @param c The character to check. 225 | */ 226 | public static boolean isXML11NCName(int c) { 227 | return (c < 0x10000 && (XML11CHARS[c] & MASK_XML11_NCNAME) != 0) 228 | || (0x10000 <= c && c < 0xF0000); 229 | } 230 | 231 | /** 232 | * Returns whether the given character is a valid 233 | * high surrogate for a name character. This includes 234 | * all high surrogates for characters [0x10000-0xEFFFF]. 235 | * In other words everything excluding planes 15 and 16. 236 | * 237 | * @param c The character to check. 238 | */ 239 | public static boolean isXML11NameHighSurrogate(int c) { 240 | return (0xD800 <= c && c <= 0xDB7F); 241 | } 242 | 243 | /** 244 | * Check to see if a string is a valid Name 245 | * 246 | * @param name string to check 247 | * @return true if name is a valid Name 248 | */ 249 | public static boolean isXML11ValidName(String name) { 250 | int length = name.length(); 251 | if (length == 0) 252 | return false; 253 | int i = 1; 254 | char ch = name.charAt(0); 255 | if( !isXML11NameStart(ch) ) { 256 | if ( length > 1 && isXML11NameHighSurrogate(ch) ) { 257 | char ch2 = name.charAt(1); 258 | if ( !XMLChar.isLowSurrogate(ch2) || 259 | !isXML11NameStart(XMLChar.supplemental(ch, ch2)) ) { 260 | return false; 261 | } 262 | i = 2; 263 | } 264 | else { 265 | return false; 266 | } 267 | } 268 | while (i < length) { 269 | ch = name.charAt(i); 270 | if ( !isXML11Name(ch) ) { 271 | if ( ++i < length && isXML11NameHighSurrogate(ch) ) { 272 | char ch2 = name.charAt(i); 273 | if ( !XMLChar.isLowSurrogate(ch2) || 274 | !isXML11Name(XMLChar.supplemental(ch, ch2)) ) { 275 | return false; 276 | } 277 | } 278 | else { 279 | return false; 280 | } 281 | } 282 | ++i; 283 | } 284 | return true; 285 | } 286 | 287 | 288 | /** 289 | * Check to see if a string is a valid NCName 290 | * 291 | * @param ncName string to check 292 | * @return true if name is a valid NCName 293 | */ 294 | public static boolean isXML11ValidNCName(String ncName) { 295 | int length = ncName.length(); 296 | if (length == 0) 297 | return false; 298 | int i = 1; 299 | char ch = ncName.charAt(0); 300 | if( !isXML11NCNameStart(ch) ) { 301 | if ( length > 1 && isXML11NameHighSurrogate(ch) ) { 302 | char ch2 = ncName.charAt(1); 303 | if ( !XMLChar.isLowSurrogate(ch2) || 304 | !isXML11NCNameStart(XMLChar.supplemental(ch, ch2)) ) { 305 | return false; 306 | } 307 | i = 2; 308 | } 309 | else { 310 | return false; 311 | } 312 | } 313 | while (i < length) { 314 | ch = ncName.charAt(i); 315 | if ( !isXML11NCName(ch) ) { 316 | if ( ++i < length && isXML11NameHighSurrogate(ch) ) { 317 | char ch2 = ncName.charAt(i); 318 | if ( !XMLChar.isLowSurrogate(ch2) || 319 | !isXML11NCName(XMLChar.supplemental(ch, ch2)) ) { 320 | return false; 321 | } 322 | } 323 | else { 324 | return false; 325 | } 326 | } 327 | ++i; 328 | } 329 | return true; 330 | } 331 | 332 | 333 | /** 334 | * Check to see if a string is a valid Nmtoken 335 | * 336 | * @param nmtoken string to check 337 | * @return true if nmtoken is a valid Nmtoken 338 | */ 339 | public static boolean isXML11ValidNmtoken(String nmtoken) { 340 | int length = nmtoken.length(); 341 | if (length == 0) 342 | return false; 343 | for (int i = 0; i < length; ++i ) { 344 | char ch = nmtoken.charAt(i); 345 | if( !isXML11Name(ch) ) { 346 | if ( ++i < length && isXML11NameHighSurrogate(ch) ) { 347 | char ch2 = nmtoken.charAt(i); 348 | if ( !XMLChar.isLowSurrogate(ch2) || 349 | !isXML11Name(XMLChar.supplemental(ch, ch2)) ) { 350 | return false; 351 | } 352 | } 353 | else { 354 | return false; 355 | } 356 | } 357 | } 358 | return true; 359 | } 360 | 361 | } 362 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/xml/XmlNamespaceContext.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.common.xcontent.xml; 2 | 3 | import javax.xml.namespace.NamespaceContext; 4 | import java.util.Enumeration; 5 | import java.util.HashSet; 6 | import java.util.Iterator; 7 | import java.util.Map; 8 | import java.util.MissingResourceException; 9 | import java.util.ResourceBundle; 10 | import java.util.Set; 11 | import java.util.SortedMap; 12 | import java.util.TreeMap; 13 | 14 | /** 15 | * Contains a simple context for XML namespaces 16 | * 17 | */ 18 | public class XmlNamespaceContext implements NamespaceContext { 19 | 20 | private static final String DEFAULT_RESOURCE = "xml-namespaces"; 21 | 22 | private final SortedMap namespaces = new TreeMap<>(); 23 | 24 | private final SortedMap> prefixes = new TreeMap<>(); 25 | 26 | protected XmlNamespaceContext() { 27 | } 28 | 29 | protected XmlNamespaceContext(ResourceBundle bundle) { 30 | Enumeration en = bundle.getKeys(); 31 | while (en.hasMoreElements()) { 32 | String prefix = en.nextElement(); 33 | String namespace = bundle.getString(prefix); 34 | addNamespace(prefix, namespace); 35 | } 36 | } 37 | 38 | protected static String bundleName() { 39 | return DEFAULT_RESOURCE; 40 | } 41 | 42 | /** 43 | * Empty namespace context. 44 | * 45 | * @return a namespace context instance 46 | */ 47 | public static XmlNamespaceContext newInstance() { 48 | return new XmlNamespaceContext(); 49 | } 50 | 51 | /** 52 | * Default namespaces from default resource bundle. 53 | * @return a namespace context instance 54 | */ 55 | public static XmlNamespaceContext getDefaultInstance() { 56 | return newInstance(bundleName()); 57 | } 58 | 59 | /** 60 | * Namespaces from given resource bundle name. 61 | * @return a namespace context instance 62 | */ 63 | public static XmlNamespaceContext newInstance(String bundleName) { 64 | try { 65 | return new XmlNamespaceContext(ResourceBundle.getBundle(bundleName)); 66 | } catch (MissingResourceException e) { 67 | return new XmlNamespaceContext(); 68 | } 69 | } 70 | 71 | public final synchronized void addNamespace(String prefix, String namespace) { 72 | namespaces.put(prefix, namespace); 73 | if (prefixes.containsKey(namespace)) { 74 | prefixes.get(namespace).add(prefix); 75 | } else { 76 | Set set = new HashSet(); 77 | set.add(prefix); 78 | prefixes.put(namespace, set); 79 | } 80 | } 81 | 82 | public Map getNamespaces() { 83 | return namespaces; 84 | } 85 | 86 | @Override 87 | public String getNamespaceURI(String prefix) { 88 | if (prefix == null) { 89 | return null; 90 | } 91 | return namespaces.containsKey(prefix) ? namespaces.get(prefix) : null; 92 | } 93 | 94 | @Override 95 | public String getPrefix(String namespaceURI) { 96 | Iterator it = getPrefixes(namespaceURI); 97 | return it != null && it.hasNext() ? it.next() : null; 98 | } 99 | 100 | @Override 101 | public Iterator getPrefixes(String namespace) { 102 | if (namespace == null) { 103 | throw new IllegalArgumentException("namespace URI cannot be null"); 104 | } 105 | return prefixes.containsKey(namespace) ? 106 | prefixes.get(namespace).iterator() : null; 107 | } 108 | 109 | public String toString() { 110 | return namespaces.toString(); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/xml/XmlXContent.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.common.xcontent.xml; 2 | 3 | import com.ctc.wstx.stax.WstxInputFactory; 4 | import com.ctc.wstx.stax.WstxOutputFactory; 5 | import com.fasterxml.jackson.core.JsonEncoding; 6 | import com.fasterxml.jackson.dataformat.xml.XmlFactory; 7 | import org.elasticsearch.common.bytes.BytesReference; 8 | import org.elasticsearch.common.io.FastStringReader; 9 | import org.elasticsearch.common.xcontent.XContent; 10 | import org.elasticsearch.common.xcontent.XContentType; 11 | import org.xbib.elasticsearch.common.xcontent.XmlXContentBuilder; 12 | import org.elasticsearch.common.xcontent.XContentGenerator; 13 | import org.elasticsearch.common.xcontent.XContentParser; 14 | 15 | import javax.xml.stream.XMLInputFactory; 16 | import javax.xml.stream.XMLOutputFactory; 17 | import java.io.IOException; 18 | import java.io.InputStream; 19 | import java.io.OutputStream; 20 | import java.io.Reader; 21 | 22 | /** 23 | * A XML based content implementation using Jackson XML dataformat 24 | * 25 | */ 26 | public class XmlXContent implements XContent { 27 | 28 | /* 29 | * This is a bit tricky. We want Woodstox. Woodstox is stax2-api, and can indent XML. We package it in the plugin. 30 | * But how can we force to load Woodstox instead of internal com.sun JDK streaming XML parser? 31 | * 32 | * 1) Elasticsearch runs the JVM in a "parent" classpath and a plugin in a separate "child" classpath. 33 | * 2) the Java XML API under XMLInputFactory.newInstance() / XMLOutputFactory.newInstance() 34 | * uses a mixture of META-INF/services and system property configuration. 35 | * Both work only on Elasticsearch parent classloader. They can not use resources inside a plugin. 36 | * So, XML factory lookup does only work on the ES "lib" folder. 37 | * 3) com.fasterxml.jackson.dataformat.xml.XmlFactory creates internal XMLStreamWriter instances to create an 38 | * indenting XML stream in the generator. We need XMLStreamWriter2 for indentation. 39 | * But XmlFactory uses the ES parent class loader because it's JDK code in javax.xml.stream that tries to load it. 40 | * Therefore, XML indentation crashes with: 41 | * java.lang.UnsupportedOperationException: Not implemented 42 | * at org.codehaus.stax2.ri.Stax2WriterAdapter.writeRaw(Stax2WriterAdapter.java:380) 43 | * because it only sees the Stax API implementation of the JDK, not Woodstox of the plugin. 44 | * 4) We can work around it by: 45 | * a) setting system properties in this static initializer (as early as possible) 46 | * b) use direct initialization of WstxInputFactory / WstxOutputFactory, no javax.xml.stream class loading 47 | */ 48 | static { 49 | System.setProperty("javax.xml.stream.XMLInputFactory", WstxInputFactory.class.getName()); 50 | System.setProperty("javax.xml.stream.XMLOutputFactory", WstxOutputFactory.class.getName()); 51 | 52 | XMLInputFactory inputFactory = new WstxInputFactory(); // do not use XMLInputFactory.newInstance() 53 | inputFactory.setProperty("javax.xml.stream.isNamespaceAware", Boolean.TRUE); 54 | inputFactory.setProperty("javax.xml.stream.isValidating", Boolean.FALSE); 55 | inputFactory.setProperty("javax.xml.stream.isCoalescing", Boolean.TRUE); 56 | inputFactory.setProperty("javax.xml.stream.isReplacingEntityReferences", Boolean.FALSE); 57 | inputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", Boolean.FALSE); 58 | 59 | XMLOutputFactory outputFactory = new WstxOutputFactory(); // do not use XMLOutputFactory.newInstance() 60 | outputFactory.setProperty("javax.xml.stream.isRepairingNamespaces", Boolean.TRUE); 61 | 62 | xmlFactory = new XmlFactory(inputFactory, outputFactory); 63 | 64 | xmlXContent = new XmlXContent(); 65 | } 66 | 67 | public static XmlXContentBuilder contentBuilder() throws IOException { 68 | return XmlXContentBuilder.builder(xmlXContent); 69 | } 70 | 71 | public static XmlXContentBuilder contentBuilder(XmlXParams params) throws IOException { 72 | XmlXContentBuilder builder = XmlXContentBuilder.builder(xmlXContent); 73 | ((XmlXContentGenerator) builder.generator()).setParams(params); 74 | return builder; 75 | } 76 | 77 | private final static XmlFactory xmlFactory; 78 | 79 | private final static XmlXContent xmlXContent; 80 | 81 | private XmlXContent() { 82 | 83 | } 84 | 85 | @Override 86 | public XContentType type() { 87 | //return XmlXContentType.XML; 88 | return null; 89 | } 90 | 91 | public static XmlXContent xmlXContent() { 92 | return xmlXContent; 93 | } 94 | 95 | protected static XmlFactory xmlFactory() { 96 | return xmlFactory; 97 | } 98 | 99 | @Override 100 | public byte streamSeparator() { 101 | throw new UnsupportedOperationException("xml does not support stream parsing..."); 102 | } 103 | 104 | @Override 105 | public XContentGenerator createGenerator(OutputStream os) throws IOException { 106 | return new XmlXContentGenerator(xmlFactory.createGenerator(os, JsonEncoding.UTF8)); 107 | } 108 | 109 | @Override 110 | public XContentGenerator createGenerator(OutputStream os, String[] filters) throws IOException { 111 | // ignore filters (for now) 112 | return new XmlXContentGenerator(xmlFactory.createGenerator(os, JsonEncoding.UTF8)); 113 | } 114 | 115 | @Override 116 | public XContentParser createParser(String content) throws IOException { 117 | return new XmlXContentParser(xmlFactory.createParser(new FastStringReader(content))); 118 | } 119 | 120 | @Override 121 | public XContentParser createParser(InputStream is) throws IOException { 122 | return new XmlXContentParser(xmlFactory.createParser(is)); 123 | } 124 | 125 | @Override 126 | public XContentParser createParser(byte[] data) throws IOException { 127 | return new XmlXContentParser(xmlFactory.createParser(data)); 128 | } 129 | 130 | @Override 131 | public XContentParser createParser(byte[] data, int offset, int length) throws IOException { 132 | return new XmlXContentParser(xmlFactory.createParser(data, offset, length)); 133 | } 134 | 135 | @Override 136 | public XContentParser createParser(BytesReference bytes) throws IOException { 137 | if (bytes.hasArray()) { 138 | return createParser(bytes.array(), bytes.arrayOffset(), bytes.length()); 139 | } 140 | return createParser(bytes.streamInput()); 141 | } 142 | 143 | @Override 144 | public XContentParser createParser(Reader reader) throws IOException { 145 | return new XmlXContentParser(xmlFactory.createParser(reader)); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/xml/XmlXContentGenerator.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.common.xcontent.xml; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; 5 | import org.elasticsearch.common.bytes.BytesReference; 6 | import org.elasticsearch.common.logging.ESLogger; 7 | import org.elasticsearch.common.logging.ESLoggerFactory; 8 | import org.elasticsearch.common.xcontent.XContentGenerator; 9 | import org.elasticsearch.common.xcontent.XContentType; 10 | import org.elasticsearch.common.xcontent.XContentParser; 11 | import org.elasticsearch.common.xcontent.XContentString; 12 | 13 | import javax.xml.namespace.QName; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | 17 | /** 18 | * 19 | * Content generator for XML format 20 | * 21 | */ 22 | public class XmlXContentGenerator implements XContentGenerator { 23 | 24 | private final static ESLogger logger = ESLoggerFactory.getLogger(XmlXContentGenerator.class.getName()); 25 | 26 | protected final ToXmlGenerator generator; 27 | 28 | private XmlXParams params; 29 | 30 | private boolean started; 31 | 32 | private boolean context; 33 | 34 | private String prefix; 35 | 36 | public XmlXContentGenerator(ToXmlGenerator generator) { 37 | this.generator = generator; 38 | this.params = new XmlXParams(); 39 | this.started = false; 40 | this.context = false; 41 | this.prefix = null; 42 | generator.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, false); 43 | } 44 | 45 | public XmlXContentGenerator setParams(XmlXParams params) { 46 | this.params = params; 47 | return this; 48 | } 49 | 50 | public XmlNamespaceContext getNamespaceContext() { 51 | return params.getNamespaceContext(); 52 | } 53 | 54 | @Override 55 | public XContentType contentType() { 56 | //return XmlXContentType.XML; 57 | return null; 58 | } 59 | 60 | @Override 61 | public void usePrettyPrint() { 62 | generator.useDefaultPrettyPrinter(); 63 | } 64 | 65 | @Override 66 | public void usePrintLineFeedAtEnd() { 67 | // nothing here 68 | } 69 | 70 | @Override 71 | public void writeStartArray() throws IOException { 72 | generator.writeStartArray(); 73 | } 74 | 75 | @Override 76 | public void writeEndArray() throws IOException { 77 | generator.writeEndArray(); 78 | } 79 | 80 | @Override 81 | public void writeStartObject() throws IOException { 82 | try { 83 | if (!started) { 84 | generator.getStaxWriter().setDefaultNamespace(params.getQName().getNamespaceURI()); 85 | generator.startWrappedValue(null, params.getQName()); 86 | } 87 | generator.writeStartObject(); 88 | if (!started ) { 89 | if (getNamespaceContext() != null && getNamespaceContext().getNamespaces() != null) { 90 | for (String prefix : getNamespaceContext().getNamespaces().keySet()) { 91 | generator.getStaxWriter().writeNamespace(prefix, getNamespaceContext().getNamespaceURI(prefix)); 92 | } 93 | } 94 | started = true; 95 | } 96 | } catch (Exception e) { 97 | logger.warn(e.getMessage(), e); 98 | } 99 | } 100 | 101 | @Override 102 | public void writeEndObject() throws IOException { 103 | generator.writeEndObject(); 104 | context = false; 105 | } 106 | 107 | @Override 108 | public void writeFieldName(String name) throws IOException { 109 | writeFieldNameXml(name); 110 | } 111 | 112 | @Override 113 | public void writeFieldName(XContentString name) throws IOException { 114 | writeFieldNameXml(name.getValue()); 115 | } 116 | 117 | @Override 118 | public void writeString(String text) throws IOException { 119 | try { 120 | generator.writeString(text); 121 | if (context && prefix != null) { 122 | params.getNamespaceContext().addNamespace(prefix, text); 123 | generator.getStaxWriter().writeNamespace(prefix, text); 124 | prefix = null; 125 | } 126 | } catch (Exception e) { 127 | logger.warn(e.getMessage() + ": " + text, e); 128 | } 129 | } 130 | 131 | @Override 132 | public void writeString(char[] text, int offset, int len) throws IOException { 133 | String s = new String(text, offset, len); 134 | try { 135 | generator.writeString(s); 136 | if (context && prefix != null) { 137 | params.getNamespaceContext().addNamespace(prefix, s); 138 | generator.getStaxWriter().writeNamespace(prefix, s); 139 | prefix = null; 140 | } 141 | } catch (Exception e) { 142 | logger.warn(e.getMessage() + ": " + s, e); 143 | } 144 | } 145 | 146 | @Override 147 | public void writeUTF8String(byte[] text, int offset, int length) throws IOException { 148 | String s = new String(text, offset, length); 149 | try { 150 | generator.writeUTF8String(text, offset, length); 151 | if (context && prefix != null) { 152 | params.getNamespaceContext().addNamespace(prefix, s); 153 | generator.getStaxWriter().writeNamespace(prefix, s); 154 | prefix = null; 155 | } 156 | } catch (Exception e) { 157 | logger.warn(e.getMessage() + ": " + s, e); 158 | } 159 | } 160 | 161 | @Override 162 | public void writeBinary(byte[] data, int offset, int len) throws IOException { 163 | generator.writeBinary(data, offset, len); 164 | } 165 | 166 | @Override 167 | public void writeBinary(byte[] data) throws IOException { 168 | generator.writeBinary(data); 169 | } 170 | 171 | @Override 172 | public void writeNumber(int v) throws IOException { 173 | generator.writeNumber(v); 174 | } 175 | 176 | @Override 177 | public void writeNumber(long v) throws IOException { 178 | generator.writeNumber(v); 179 | } 180 | 181 | @Override 182 | public void writeNumber(double d) throws IOException { 183 | generator.writeNumber(d); 184 | } 185 | 186 | @Override 187 | public void writeNumber(float f) throws IOException { 188 | generator.writeNumber(f); 189 | } 190 | 191 | @Override 192 | public void writeBoolean(boolean state) throws IOException { 193 | generator.writeBoolean(state); 194 | } 195 | 196 | @Override 197 | public void writeBooleanField(XContentString fieldName, boolean value) throws IOException { 198 | writeFieldName(fieldName); 199 | generator.writeBoolean(value); 200 | } 201 | 202 | @Override 203 | public void writeNull() throws IOException { 204 | generator.writeNull(); 205 | } 206 | 207 | @Override 208 | public void writeNullField(XContentString fieldName) throws IOException { 209 | writeFieldName(fieldName); 210 | generator.writeNull(); 211 | } 212 | 213 | @Override 214 | public void writeStringField(String fieldName, String value) throws IOException { 215 | try { 216 | generator.writeStringField(fieldName, value); 217 | if (context && value != null) { 218 | params.getNamespaceContext().addNamespace(fieldName, value); 219 | generator.getStaxWriter().writeNamespace(fieldName, value); 220 | } 221 | } catch (Exception e) { 222 | logger.warn(e.getMessage() + ": " + fieldName + "=" + value, e); 223 | } 224 | } 225 | 226 | @Override 227 | public void writeStringField(XContentString fieldName, String value) throws IOException { 228 | writeFieldName(fieldName); 229 | generator.writeString(value); 230 | } 231 | 232 | @Override 233 | public void writeBooleanField(String fieldName, boolean value) throws IOException { 234 | generator.writeBooleanField(fieldName, value); 235 | } 236 | 237 | @Override 238 | public void writeNullField(String fieldName) throws IOException { 239 | generator.writeNullField(fieldName); 240 | } 241 | 242 | @Override 243 | public void writeNumberField(String fieldName, int value) throws IOException { 244 | generator.writeNumberField(fieldName, value); 245 | } 246 | 247 | @Override 248 | public void writeNumberField(XContentString fieldName, int value) throws IOException { 249 | writeFieldName(fieldName); 250 | generator.writeNumber(value); 251 | } 252 | 253 | @Override 254 | public void writeNumberField(String fieldName, long value) throws IOException { 255 | generator.writeNumberField(fieldName, value); 256 | } 257 | 258 | @Override 259 | public void writeNumberField(XContentString fieldName, long value) throws IOException { 260 | writeFieldName(fieldName); 261 | generator.writeNumber(value); 262 | } 263 | 264 | @Override 265 | public void writeNumberField(String fieldName, double value) throws IOException { 266 | generator.writeNumberField(fieldName, value); 267 | } 268 | 269 | @Override 270 | public void writeNumberField(String fieldName, float value) throws IOException { 271 | generator.writeNumberField(fieldName, value); 272 | } 273 | 274 | @Override 275 | public void writeBinaryField(String fieldName, byte[] data) throws IOException { 276 | generator.writeBinaryField(fieldName, data); 277 | } 278 | 279 | @Override 280 | public void writeBinaryField(XContentString fieldName, byte[] value) throws IOException { 281 | writeFieldName(fieldName); 282 | generator.writeBinary(value); 283 | } 284 | 285 | @Override 286 | public void writeNumberField(XContentString fieldName, double value) throws IOException { 287 | writeFieldName(fieldName); 288 | generator.writeNumber(value); 289 | } 290 | 291 | @Override 292 | public void writeNumberField(XContentString fieldName, float value) throws IOException { 293 | writeFieldName(fieldName); 294 | generator.writeNumber(value); 295 | } 296 | 297 | public void writeArrayFieldStart(String fieldName) throws IOException { 298 | generator.writeArrayFieldStart(fieldName); 299 | } 300 | 301 | @Override 302 | public void writeArrayFieldStart(XContentString fieldName) throws IOException { 303 | writeFieldName(fieldName); 304 | generator.writeStartArray(); 305 | } 306 | 307 | public void writeObjectFieldStart(String fieldName) throws IOException { 308 | generator.writeObjectFieldStart(fieldName); 309 | } 310 | 311 | @Override 312 | public void writeObjectFieldStart(XContentString fieldName) throws IOException { 313 | writeFieldName(fieldName); 314 | generator.writeStartObject(); 315 | } 316 | 317 | @Override 318 | public void writeRawField(String fieldName, InputStream content) throws IOException { 319 | writeFieldNameXml(fieldName); 320 | try (JsonParser parser = XmlXContent.xmlFactory().createParser(content)) { 321 | parser.nextToken(); 322 | generator.copyCurrentStructure(parser); 323 | } 324 | } 325 | 326 | @Override 327 | public void writeRawField(String fieldName, BytesReference content) throws IOException { 328 | writeFieldNameXml(fieldName); 329 | try (JsonParser parser = XmlXContent.xmlFactory().createParser(content.toBytes())) { 330 | parser.nextToken(); 331 | generator.copyCurrentStructure(parser); 332 | } 333 | } 334 | 335 | @Override 336 | public void writeRawValue(BytesReference content) throws IOException { 337 | generator.writeRawValue(content.toUtf8()); 338 | } 339 | 340 | @Override 341 | public void copyCurrentStructure(XContentParser parser) throws IOException { 342 | if (parser.currentToken() == null) { 343 | parser.nextToken(); 344 | } 345 | if (parser instanceof XmlXContentParser) { 346 | generator.copyCurrentStructure(((XmlXContentParser) parser).parser); 347 | } else { 348 | copyCurrentStructure(this, parser); 349 | } 350 | } 351 | 352 | public static void copyCurrentStructure(XContentGenerator generator, XContentParser parser) throws IOException { 353 | XContentParser.Token t = parser.currentToken(); 354 | 355 | // Let's handle field-name separately first 356 | if (t == XContentParser.Token.FIELD_NAME) { 357 | generator.writeFieldName(parser.currentName()); 358 | t = parser.nextToken(); 359 | // fall-through to copy the associated value 360 | } 361 | 362 | switch (t) { 363 | case START_ARRAY: 364 | generator.writeStartArray(); 365 | while (parser.nextToken() != XContentParser.Token.END_ARRAY) { 366 | copyCurrentStructure(generator, parser); 367 | } 368 | generator.writeEndArray(); 369 | break; 370 | case START_OBJECT: 371 | generator.writeStartObject(); 372 | while (parser.nextToken() != XContentParser.Token.END_OBJECT) { 373 | copyCurrentStructure(generator, parser); 374 | } 375 | generator.writeEndObject(); 376 | break; 377 | default: // others are simple: 378 | copyCurrentEvent(generator, parser); 379 | } 380 | } 381 | 382 | public static void copyCurrentEvent(XContentGenerator generator, XContentParser parser) throws IOException { 383 | switch (parser.currentToken()) { 384 | case START_OBJECT: 385 | generator.writeStartObject(); 386 | break; 387 | case END_OBJECT: 388 | generator.writeEndObject(); 389 | break; 390 | case START_ARRAY: 391 | generator.writeStartArray(); 392 | break; 393 | case END_ARRAY: 394 | generator.writeEndArray(); 395 | break; 396 | case FIELD_NAME: 397 | generator.writeFieldName(parser.currentName()); 398 | break; 399 | case VALUE_STRING: 400 | if (parser.hasTextCharacters()) { 401 | generator.writeString(parser.textCharacters(), parser.textOffset(), parser.textLength()); 402 | } else { 403 | generator.writeString(parser.text()); 404 | } 405 | break; 406 | case VALUE_NUMBER: 407 | switch (parser.numberType()) { 408 | case INT: 409 | generator.writeNumber(parser.intValue()); 410 | break; 411 | case LONG: 412 | generator.writeNumber(parser.longValue()); 413 | break; 414 | case FLOAT: 415 | generator.writeNumber(parser.floatValue()); 416 | break; 417 | case DOUBLE: 418 | generator.writeNumber(parser.doubleValue()); 419 | break; 420 | } 421 | break; 422 | case VALUE_BOOLEAN: 423 | generator.writeBoolean(parser.booleanValue()); 424 | break; 425 | case VALUE_NULL: 426 | generator.writeNull(); 427 | break; 428 | case VALUE_EMBEDDED_OBJECT: 429 | generator.writeBinary(parser.binaryValue()); 430 | } 431 | } 432 | 433 | @Override 434 | public void flush() throws IOException { 435 | generator.flush(); 436 | } 437 | 438 | @Override 439 | public void close() throws IOException { 440 | generator.close(); 441 | } 442 | 443 | private void writeFieldNameXml(String name) throws IOException { 444 | if (!context) { 445 | this.context = "@context".equals(name); 446 | this.prefix = null; 447 | } 448 | if (name.startsWith("@")) { 449 | // setting to attribute is simple but tricky, it allows to declare namespaces in StaX 450 | generator.setNextIsAttribute(true); 451 | } else if (context) { 452 | prefix = name; 453 | } 454 | QName qname = toQName(name); 455 | generator.setNextName(qname); 456 | generator.writeFieldName(qname.getLocalPart()); 457 | } 458 | 459 | private QName toQName(String name) throws IOException { 460 | QName root = params.getQName(); 461 | XmlNamespaceContext context = params.getNamespaceContext(); 462 | String nsPrefix = root.getPrefix(); 463 | String nsURI = root.getNamespaceURI(); 464 | if (name.startsWith("_") || name.startsWith("@")) { 465 | name = name.substring(1); 466 | } 467 | name = ISO9075.encode(name); 468 | int pos = name.indexOf(':'); 469 | if (pos > 0) { 470 | nsPrefix = name.substring(0, pos); 471 | nsURI = context != null ? context.getNamespaceURI(nsPrefix) : XmlXParams.DEFAULT_ROOT.getNamespaceURI(); 472 | if (nsURI == null) { 473 | throw new IOException("unknown namespace prefix: " + nsPrefix); 474 | } 475 | name = name.substring(pos + 1); 476 | } 477 | return new QName(nsURI, name, nsPrefix); 478 | } 479 | } 480 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/xml/XmlXContentParser.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.common.xcontent.xml; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.JsonToken; 5 | import org.apache.lucene.util.BytesRef; 6 | import org.elasticsearch.common.xcontent.XContentLocation; 7 | import org.elasticsearch.common.xcontent.XContentParser; 8 | import org.elasticsearch.common.xcontent.XContentType; 9 | import org.elasticsearch.common.xcontent.support.AbstractXContentParser; 10 | 11 | import java.io.IOException; 12 | import java.nio.CharBuffer; 13 | 14 | public class XmlXContentParser extends AbstractXContentParser { 15 | 16 | final JsonParser parser; 17 | 18 | public XmlXContentParser(JsonParser parser) { 19 | this.parser = parser; 20 | } 21 | 22 | @Override 23 | public XContentType contentType() { 24 | //return XmlXContentType.XML; 25 | return null; 26 | } 27 | 28 | @Override 29 | public XContentParser.Token nextToken() throws IOException { 30 | return convertToken(parser.nextToken()); 31 | } 32 | 33 | @Override 34 | public void skipChildren() throws IOException { 35 | parser.skipChildren(); 36 | } 37 | 38 | @Override 39 | public XContentParser.Token currentToken() { 40 | return convertToken(parser.getCurrentToken()); 41 | } 42 | 43 | @Override 44 | public XContentParser.NumberType numberType() throws IOException { 45 | return convertNumberType(parser.getNumberType()); 46 | } 47 | 48 | @Override 49 | public String currentName() throws IOException { 50 | return parser.getCurrentName(); 51 | } 52 | 53 | @Override 54 | protected boolean doBooleanValue() throws IOException { 55 | return parser.getBooleanValue(); 56 | } 57 | 58 | @Override 59 | public String text() throws IOException { 60 | return parser.getText(); 61 | } 62 | 63 | @Override 64 | public BytesRef utf8Bytes() throws IOException { 65 | return new BytesRef(CharBuffer.wrap(parser.getTextCharacters(), parser.getTextOffset(), parser.getTextLength())); 66 | } 67 | 68 | @Override 69 | public Object objectText() throws IOException { 70 | JsonToken currentToken = parser.getCurrentToken(); 71 | if (currentToken == JsonToken.VALUE_STRING) { 72 | return text(); 73 | } else if (currentToken == JsonToken.VALUE_NUMBER_INT || currentToken == JsonToken.VALUE_NUMBER_FLOAT) { 74 | return parser.getNumberValue(); 75 | } else if (currentToken == JsonToken.VALUE_TRUE) { 76 | return Boolean.TRUE; 77 | } else if (currentToken == JsonToken.VALUE_FALSE) { 78 | return Boolean.FALSE; 79 | } else if (currentToken == JsonToken.VALUE_NULL) { 80 | return null; 81 | } else { 82 | return text(); 83 | } 84 | } 85 | 86 | @Override 87 | public Object objectBytes() throws IOException { 88 | JsonToken currentToken = parser.getCurrentToken(); 89 | if (currentToken == JsonToken.VALUE_STRING) { 90 | return utf8Bytes(); 91 | } else if (currentToken == JsonToken.VALUE_NUMBER_INT || currentToken == JsonToken.VALUE_NUMBER_FLOAT) { 92 | return parser.getNumberValue(); 93 | } else if (currentToken == JsonToken.VALUE_TRUE) { 94 | return Boolean.TRUE; 95 | } else if (currentToken == JsonToken.VALUE_FALSE) { 96 | return Boolean.FALSE; 97 | } else if (currentToken == JsonToken.VALUE_NULL) { 98 | return null; 99 | } else { 100 | return utf8Bytes(); 101 | } 102 | } 103 | 104 | @Override 105 | public boolean hasTextCharacters() { 106 | return parser.hasTextCharacters(); 107 | } 108 | 109 | @Override 110 | public char[] textCharacters() throws IOException { 111 | return parser.getTextCharacters(); 112 | } 113 | 114 | @Override 115 | public int textLength() throws IOException { 116 | return parser.getTextLength(); 117 | } 118 | 119 | @Override 120 | public int textOffset() throws IOException { 121 | return parser.getTextOffset(); 122 | } 123 | 124 | @Override 125 | public Number numberValue() throws IOException { 126 | return parser.getNumberValue(); 127 | } 128 | 129 | @Override 130 | public short doShortValue() throws IOException { 131 | return parser.getShortValue(); 132 | } 133 | 134 | @Override 135 | public int doIntValue() throws IOException { 136 | return parser.getIntValue(); 137 | } 138 | 139 | @Override 140 | public long doLongValue() throws IOException { 141 | return parser.getLongValue(); 142 | } 143 | 144 | @Override 145 | public float doFloatValue() throws IOException { 146 | return parser.getFloatValue(); 147 | } 148 | 149 | @Override 150 | public double doDoubleValue() throws IOException { 151 | return parser.getDoubleValue(); 152 | } 153 | 154 | @Override 155 | public boolean isClosed() { 156 | return parser.isClosed(); 157 | } 158 | 159 | @Override 160 | public byte[] binaryValue() throws IOException { 161 | return parser.getBinaryValue(); 162 | } 163 | 164 | @Override 165 | public XContentLocation getTokenLocation() { 166 | return null; 167 | } 168 | 169 | @Override 170 | public void close() { 171 | try { 172 | parser.close(); 173 | } catch (IOException e) { 174 | // ignore 175 | } 176 | } 177 | 178 | private NumberType convertNumberType(JsonParser.NumberType numberType) { 179 | switch (numberType) { 180 | case INT: 181 | return NumberType.INT; 182 | case LONG: 183 | return NumberType.LONG; 184 | case FLOAT: 185 | return NumberType.FLOAT; 186 | case DOUBLE: 187 | return NumberType.DOUBLE; 188 | } 189 | throw new IllegalStateException("No matching token for number_type [" + numberType + "]"); 190 | } 191 | 192 | private Token convertToken(JsonToken token) { 193 | if (token == null) { 194 | return null; 195 | } 196 | switch (token) { 197 | case FIELD_NAME: 198 | return Token.FIELD_NAME; 199 | case VALUE_FALSE: 200 | case VALUE_TRUE: 201 | return Token.VALUE_BOOLEAN; 202 | case VALUE_STRING: 203 | return Token.VALUE_STRING; 204 | case VALUE_NUMBER_INT: 205 | case VALUE_NUMBER_FLOAT: 206 | return Token.VALUE_NUMBER; 207 | case VALUE_NULL: 208 | return Token.VALUE_NULL; 209 | case START_OBJECT: 210 | return Token.START_OBJECT; 211 | case END_OBJECT: 212 | return Token.END_OBJECT; 213 | case START_ARRAY: 214 | return Token.START_ARRAY; 215 | case END_ARRAY: 216 | return Token.END_ARRAY; 217 | case VALUE_EMBEDDED_OBJECT: 218 | return Token.VALUE_EMBEDDED_OBJECT; 219 | } 220 | throw new IllegalStateException("No matching token for json_token [" + token + "]"); 221 | } 222 | } -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/common/xcontent/xml/XmlXParams.java: -------------------------------------------------------------------------------- 1 | 2 | package org.xbib.elasticsearch.common.xcontent.xml; 3 | 4 | import javax.xml.namespace.QName; 5 | 6 | /** 7 | * XML parameters for XML XContent 8 | */ 9 | public class XmlXParams { 10 | 11 | public final static QName DEFAULT_ROOT = new QName("http://elasticsearch.org/ns/1.0/", "root", "es"); 12 | 13 | private final QName root; 14 | 15 | private XmlNamespaceContext namespaceContext; 16 | 17 | public XmlXParams() { 18 | this(null, null); 19 | } 20 | 21 | public XmlXParams(XmlNamespaceContext namespaceContext) { 22 | this(null, namespaceContext); 23 | } 24 | 25 | public XmlXParams(QName root, XmlNamespaceContext namespaceContext) { 26 | this.root = root != null ? root : DEFAULT_ROOT; 27 | if (namespaceContext == null) { 28 | namespaceContext = XmlNamespaceContext.getDefaultInstance(); 29 | namespaceContext.addNamespace(DEFAULT_ROOT.getPrefix(), DEFAULT_ROOT.getNamespaceURI()); 30 | } else { 31 | namespaceContext.addNamespace(DEFAULT_ROOT.getPrefix(), DEFAULT_ROOT.getNamespaceURI()); 32 | this.namespaceContext = namespaceContext; 33 | } 34 | } 35 | 36 | public QName getQName() { 37 | return root; 38 | } 39 | 40 | public XmlNamespaceContext getNamespaceContext() { 41 | return namespaceContext; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/plugin/xml/XmlPlugin.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.plugin.xml; 2 | 3 | import org.elasticsearch.common.component.LifecycleComponent; 4 | import org.elasticsearch.plugins.Plugin; 5 | import org.xbib.elasticsearch.rest.xml.XmlService; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | 10 | /** 11 | * XML plugin 12 | */ 13 | public class XmlPlugin extends Plugin { 14 | 15 | @Override 16 | public String name() { 17 | return "xml"; 18 | } 19 | 20 | @Override 21 | public String description() { 22 | return "XML plugin"; 23 | } 24 | 25 | @Override 26 | public Collection> nodeServices() { 27 | Collection> services = new ArrayList<>(); 28 | services.add(XmlService.class); 29 | return services; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/rest/xml/XmlFilter.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.rest.xml; 2 | 3 | import org.elasticsearch.common.bytes.BytesReference; 4 | import org.elasticsearch.common.logging.ESLogger; 5 | import org.elasticsearch.common.logging.ESLoggerFactory; 6 | import org.elasticsearch.common.xcontent.XContentBuilder; 7 | import org.elasticsearch.common.xcontent.XContentFactory; 8 | import org.elasticsearch.common.xcontent.XContentType; 9 | import org.elasticsearch.common.xcontent.XContentParser; 10 | import org.elasticsearch.http.HttpChannel; 11 | import org.elasticsearch.http.HttpRequest; 12 | import org.elasticsearch.rest.BytesRestResponse; 13 | import org.elasticsearch.rest.RestChannel; 14 | import org.elasticsearch.rest.RestFilter; 15 | import org.elasticsearch.rest.RestFilterChain; 16 | import org.elasticsearch.rest.RestRequest; 17 | import org.elasticsearch.rest.RestResponse; 18 | import org.elasticsearch.rest.RestStatus; 19 | 20 | import org.xbib.elasticsearch.common.xcontent.XmlXContentBuilder; 21 | import org.xbib.elasticsearch.common.xcontent.XmlXContentFactory; 22 | import org.xbib.elasticsearch.common.xcontent.XmlXContentType; 23 | import org.xbib.elasticsearch.common.xcontent.xml.XmlXParams; 24 | 25 | import java.util.Map; 26 | 27 | /** 28 | * XML filter for Elasticsearch REST requests and responses. 29 | * 30 | * To receive XML responses, the request header Accept: must contain "application/xml" 31 | */ 32 | public class XmlFilter extends RestFilter { 33 | 34 | private final ESLogger logger = ESLoggerFactory.getLogger(XmlFilter.class.getName()); 35 | 36 | private final XmlXParams params; 37 | 38 | public XmlFilter() { 39 | this.params = new XmlXParams(); 40 | } 41 | 42 | @Override 43 | public void process(RestRequest request, RestChannel channel, RestFilterChain filterChain) { 44 | filterChain.continueProcessing(new XmlRequest(request), new XmlChannel(request, channel)); 45 | } 46 | 47 | private boolean isXml(RestRequest request) { 48 | return "application/xml".equals(request.header("Accept")) 49 | || request.hasParam("xml"); 50 | } 51 | 52 | /** 53 | * Unwraps an XML REST request to JSON if Content-type: header declares application/xml. 54 | * We must extend HttpRequest because this will get used in a casting in the HTTP controller. 55 | */ 56 | class XmlRequest extends HttpRequest { 57 | 58 | private RestRequest request; 59 | 60 | XmlRequest(RestRequest request) { 61 | this.request = request; 62 | } 63 | 64 | @Override 65 | public Method method() { 66 | return request.method(); 67 | } 68 | 69 | @Override 70 | public String uri() { 71 | return request.uri(); 72 | } 73 | 74 | @Override 75 | public String rawPath() { 76 | return request.rawPath(); 77 | } 78 | 79 | @Override 80 | public boolean hasContent() { 81 | return request.hasContent(); 82 | } 83 | 84 | @Override 85 | public BytesReference content() { 86 | if (isXml(request)) { 87 | XContentParser parser = null; 88 | try { 89 | BytesReference b = request.content(); 90 | parser = XmlXContentFactory.xContent(XmlXContentType.XML).createParser(b); 91 | parser.nextToken(); 92 | XContentBuilder builder = XContentFactory.jsonBuilder(); 93 | builder.copyCurrentStructure(parser); 94 | return builder.bytes(); 95 | } catch (Throwable e) { 96 | logger.error(e.getMessage(), e); 97 | } finally { 98 | if (parser != null) { 99 | parser.close(); 100 | } 101 | } 102 | } 103 | return request.content(); 104 | } 105 | 106 | @Override 107 | public String header(String name) { 108 | return request.header(name); 109 | } 110 | 111 | @Override 112 | public Iterable> headers() { 113 | return request.headers(); 114 | } 115 | 116 | @Override 117 | public boolean hasParam(String key) { 118 | return false; 119 | } 120 | 121 | @Override 122 | public String param(String key) { 123 | return request.param(key); 124 | } 125 | 126 | @Override 127 | public String param(String key, String defaultValue) { 128 | return request.param(key, defaultValue); 129 | } 130 | 131 | @Override 132 | public Map params() { 133 | return request.params(); 134 | } 135 | } 136 | 137 | /** 138 | * Wraps a REST channel response into XML if Accept: header declares application/xml. 139 | * This must extend HttpChannel because this will get used in a casting in the HTTP controller. 140 | */ 141 | class XmlChannel extends HttpChannel { 142 | 143 | private final RestChannel channel; 144 | 145 | XmlChannel(RestRequest request, RestChannel channel) { 146 | super(request, true); 147 | this.channel = channel; 148 | } 149 | 150 | @Override 151 | public void sendResponse(RestResponse response) { 152 | if (!response.status().equals(RestStatus.OK)) { 153 | channel.sendResponse(response); 154 | } 155 | if (isXml(request)) { 156 | XContentParser parser = null; 157 | try { 158 | String string = response.content().toUtf8(); // takes some space ... :( 159 | XContentType xContentType = XContentFactory.xContentType(string); 160 | parser = XContentFactory.xContent(xContentType).createParser(string); 161 | parser.nextToken(); 162 | XmlXContentBuilder builder = XmlXContentFactory.xmlBuilder(params); 163 | if (request.paramAsBoolean("pretty", false)) { 164 | builder.prettyPrint(); 165 | } 166 | builder.copyCurrentStructure(parser); 167 | BytesRestResponse restResponse = new BytesRestResponse(RestStatus.OK, "text/xml; charset=UTF-8", builder.bytes()); 168 | channel.sendResponse(restResponse); 169 | return; 170 | } catch (Throwable e) { 171 | logger.error(e.getMessage(), e); 172 | channel.sendResponse(new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, e.getMessage())); 173 | return; 174 | } finally { 175 | if (parser != null) { 176 | parser.close(); 177 | } 178 | } 179 | } 180 | channel.sendResponse(response); 181 | } 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/org/xbib/elasticsearch/rest/xml/XmlService.java: -------------------------------------------------------------------------------- 1 | package org.xbib.elasticsearch.rest.xml; 2 | 3 | import org.elasticsearch.ElasticsearchException; 4 | import org.elasticsearch.common.component.AbstractLifecycleComponent; 5 | import org.elasticsearch.common.inject.Inject; 6 | import org.elasticsearch.common.settings.Settings; 7 | import org.elasticsearch.rest.RestController; 8 | 9 | public class XmlService extends AbstractLifecycleComponent { 10 | 11 | private final RestController controller; 12 | 13 | @Inject 14 | public XmlService(Settings settings, RestController controller) { 15 | super(settings); 16 | this.controller = controller; 17 | } 18 | 19 | @Override 20 | protected void doStart() throws ElasticsearchException { 21 | controller.registerFilter(new XmlFilter()); 22 | } 23 | 24 | @Override 25 | protected void doStop() throws ElasticsearchException { 26 | } 27 | 28 | @Override 29 | protected void doClose() throws ElasticsearchException { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/xml-namespaces.properties: -------------------------------------------------------------------------------- 1 | 2 | # ADD YOUR XML NAMESPACES HERE TO THIS FILE! 3 | 4 | # XML namespaces 5 | xml = http://www.w3.org/XML/1998/namespace 6 | xsl = http://www.w3.org/1999/XSL/Transform 7 | 8 | # Apache 9 | xalan = http://xml.apache.org/xslt 10 | 11 | # W3C Atom 12 | atom = http://www.w3.org/2005/Atom 13 | 14 | # some RDF namespaces 15 | rdf = http://www.w3.org/1999/02/22-rdf-syntax-ns# 16 | rdfs = http://www.w3.org/2000/01/rdf-schema# 17 | owl = http://www.w3.org/2002/07/owl# 18 | foaf = http://xmlns.com/foaf/0.1/ 19 | 20 | # Dublin Core 21 | # http://dublincore.org/documents/dcmi-namespace/ 22 | dc = http://purl.org/dc/elements/1.1/ 23 | dcterms = http://purl.org/dc/terms/ 24 | -------------------------------------------------------------------------------- /src/main/templates/plugin-descriptor.properties: -------------------------------------------------------------------------------- 1 | classname=${descriptor.classname} 2 | name=${descriptor.name} 3 | description=${descriptor.description} 4 | jvm=${descriptor.jvm} 5 | site=${descriptor.site} 6 | isolated=${descriptor.isolated} 7 | version=${descriptor.version} 8 | java.version=${descriptor.javaVersion} 9 | elasticsearch.version=${descriptor.elasticsearchVersion} 10 | --------------------------------------------------------------------------------