JAXB将非ASCII字符转换为ASCII字符

时间:2014-02-06 14:56:17

标签: java jaxb xsd locale

我有一些xsd模式,元素名称包含非ASCII字符。当我使用Eclipse Kepler使用生成JAXB Classes 命令生成java类时,生成的类和变量包含非ASCII字符。我想将这个非ASCII字符转换为ASCII字符。

我已经在JAVA_TOOL_OPTIONS

设置了语言环境
-Duser.country=GB -Duser.language=en

例如

İ -> I
Ç -> C
Ş -> S
Ö -> O
Ğ -> G
Ü -> U
ı -> i
ö -> o
ü -> u
ç -> c
ğ -> g
ş -> s

1 个答案:

答案 0 :(得分:8)

编辑: 由于要求是通用解决方案且不使用外部绑定文件,我在下面提供了 2个选项:

选项1 - 通用解决方案 - 创建自定义XJC插件以规范化

通用解决方案有效:

  1. 扩展com.sun.tools.xjc.Plugin抽象类并覆盖JAXB用于命名工件的方法 - 基本创建插件
  2. 在专门调出jar内jar文件夹的services目录中的实现名称后,将此实现打包到META-INF
  3. 将这个新创建的jar与jaxb libs一起部署并通过ANT运行(build.xml,如下所示,继续阅读)
  4. 为了您的目的,我创建了可以从here下载jar的插件,从here下载ant脚本(build.xml)。将jar放入eclipse中的构建路径并编辑ant文件,以提供JAXB库的位置,生成的类的目标包,项目名称和模式位置并运行它。 就是这样!< /强>

    <强>解释

    我使用额外的命令行选项XJC创建了一个自定义-normalize插件,用您的ASCII等效项替换创建的Java类,方法,变量,属性和接口中的重音字符

    XJC具有自定义插件创建功能,可以控制生成的类,变量等的名称,注释和其他属性。 This blog post虽然陈旧,但可以帮助您开始使用此类插件实现的基础知识。

    长话短说,我创建了一个扩展抽象com.sun.tools.xjc.Plugin类的类,重写其重要方法onActivated

    在这个方法中,我将com.sun.tools.xjc.Option#setNameConverter设置为一个自定义类,它负责覆盖获取类名称,方法等所需的方法。我已将源代码提交给git repo here好吧,下面是它的详细用法:

    import java.text.Normalizer;
    
    import org.xml.sax.ErrorHandler;
    import org.xml.sax.SAXException;
    
    import com.sun.tools.xjc.BadCommandLineException;
    import com.sun.tools.xjc.Options;
    import com.sun.tools.xjc.Plugin;
    import com.sun.tools.xjc.outline.Outline;
    import com.sun.xml.bind.api.impl.NameConverter;
    
    /**
     * {@link Plugin} that normalized the names of JAXB generated artifacts
     * 
     * @author popofibo
     */
    public class NormalizeElements extends Plugin {
    
        /**
         * Set the command line option
         */
        @Override
        public String getOptionName() {
            return "normalize";
        }
    
        /**
         * Usage content of the option
         */
        @Override
        public String getUsage() {
            return "  -normalize    :  normalize the classes and method names generated by removing the accented characters";
        }
    
        /**
         * Set the name converted option to a delegated custom implementation of
         * NameConverter.Standard
         */
        @Override
        public void onActivated(Options opts) throws BadCommandLineException {
            opts.setNameConverter(new NonAsciiConverter(), this);
        }
    
        /**
         * Always return true
         */
        @Override
        public boolean run(Outline model, Options opt, ErrorHandler errorHandler)
                throws SAXException {
            return true;
        }
    
    }
    
    /**
     * 
     * @author popofibo
     * 
     */
    class NonAsciiConverter extends NameConverter.Standard {
    
        /**
         * Override the generated class name
         */
        @Override
        public String toClassName(String s) {
            String origStr = super.toClassName(s);
            return normalize(origStr);
        }
    
        /**
         * Override the generated property name
         */
        @Override
        public String toPropertyName(String s) {
            String origStr = super.toPropertyName(s);
            return normalize(origStr);
        }
    
        /**
         * Override the generated variable name
         */
        @Override
        public String toVariableName(String s) {
            String origStr = super.toVariableName(s);
            return normalize(origStr);
        }
    
        /**
         * Override the generated interface name
         */
        @Override
        public String toInterfaceName(String s) {
            String origStr = super.toInterfaceName(s);
            return normalize(origStr);
        }
    
        /**
         * Match the accented characters within a String choosing Canonical
         * Decomposition option of the Normalizer, regex replaceAll using non POSIX
         * character classes for ASCII
         * 
         * @param accented
         * @return normalized String
         */
        private String normalize(String accented) {
            String normalized = Normalizer.normalize(accented, Normalizer.Form.NFD);
            normalized = normalized.replaceAll("[^\\p{ASCII}]", "");
            return normalized;
        }
    }
    

    要使用正常jaxb解组启用此插件,请将这些类打包到jar中,在jar中添加/META-INF/services/com.sun.tools.xjc.Plugin文件并将其放入构建路径中。

    jar中的

    /META-INF/services/com.sun.tools.xjc.Plugin文件:

    enter image description here

    此文件显示:

    com.popofibo.plugins.jaxb.NormalizeElements
    

    如前所述,我将它打包在jar中,将其部署在我的eclipse构建路径中,现在我遇到运行eclipse kepler with JDK 1.7的问题是我收到此异常(消息):< / p>

    com.sun.tools.xjc.plugin Provider <my class> not a subtype
    

    因此,最好使用ANT生成类,以下build.xml对目前为止完成的工作做出公正的准备:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <project name="SomeProject" default="createClasses">
    
        <taskdef name="xjc" classname="com.sun.tools.xjc.XJC2Task">
            <classpath>
                <pathelement
                    path="C:/Workspace/jaxb-ri-2.2.7/jaxb-ri-2.2.7/lib/jaxb-xjc.jar" />
                <pathelement
                    path="C:/Workspace/jaxb-ri-2.2.7/jaxb-ri-2.2.7/lib/jaxb-impl.jar" />
                <pathelement
                    path="C:/Workspace/jaxb-ri-2.2.7/jaxb-ri-2.2.7/lib/jaxb2-value-constructor.jar" />
                <pathelement path="C:/Workspace/normalizeplugin_xjc_v0.4.jar" />
            </classpath>
        </taskdef>
    
        <target name="clean">
            <delete dir="src/com/popofibo/jaxb" />
        </target>
    
        <target name="createClasses" depends="clean">
            <xjc schema="res/some.xsd" destdir="src" package="com.popofibo.jaxb"
                encoding="UTF-8">
                <arg value="-normalize" />
            </xjc>
        </target>
    </project>
    

    展示我选择的规范化过程的架构是:

    <xs:element name="shiporder">
      <xs:complexType>
        <xs:sequence>
          <xs:element name="Örderperson" type="xs:string"/>
          <xs:element name="Şhİpto">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="name" type="xs:string"/>
                <xs:element name="address" type="xs:string"/>
                <xs:element name="Çity" type="xs:string"/>
                <xs:element name="ÇoÜntry" type="xs:string"/>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
          <xs:element name="İtem" maxOccurs="unbounded">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="title" type="xs:string"/>
                <xs:element name="note" type="xs:string" minOccurs="0"/>
                <xs:element name="qÜantity" type="xs:positiveInteger"/>
                <xs:element name="price" type="xs:decimal"/>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
        <xs:attribute name="orderid" type="xs:string" use="required"/>
      </xs:complexType>
    </xs:element>
    
    </xs:schema> 
    

    正如你所看到的,我已经设置了参数和包,我想要生成我的类,并且瞧 - 生成的工件中的类,方法,变量的ASCII名称(我看到的唯一差距是XML注释不会影响原因但也很容易克服):

    enter image description here

    上面的屏幕截图显示了名称已经过标准化,并被其ASCII对应的名称替换(要查看没有替换的内容,请参阅选项2中的屏幕截图)。

    选项2 - 使用外部绑定文件

    要删除重音字符,您可以创建自定义绑定文件,并在生成类时使用它绑定类和属性名称。请参阅:Creating an External Binding Declarations File Using JAXB Binding Declarations

    我使用选项1 中已经提到的xsd,其元素名称包含“重音”(非ASCII)字符:

    如果我在没有指定外部绑定的情况下生成类,我会得到以下输出:

    enter image description here

    现在,如果我更改绑定以生成我选择的类名和变量,我将binding.xml写为:

    <jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
        <jxb:globalBindings localScoping="toplevel" />
    
        <jxb:bindings schemaLocation="some.xsd">
            <jxb:bindings node="//xs:element[@name='Şhİpto']">
                <jxb:class name="ShipTo" />
            </jxb:bindings>
            <jxb:bindings node="//xs:element[@name='Örderperson']">
                <jxb:property name="OrderPerson" />
            </jxb:bindings>
            <jxb:bindings node="//xs:element[@name='Şhİpto']//xs:complexType">
                <jxb:class name="ShipToo" />
            </jxb:bindings>
        </jxb:bindings>
    
    </jxb:bindings>
    

    现在我通过指定绑定文件来生成我的类:

    enter image description here

    在接下来的步骤中,我选择了包和我得到的绑定文件,

    enter image description here

    注意:如果您没有使用eclipse生成类,则可能需要检查xjc binding compiler以使用外部绑定文件。