3

Jackson と Woodstox を使用して (ドキュメントの推奨に従って) 読み取り、編集、書き込みを行うための指示が記載された XML ファイルを受け取りました。ほとんどの場合、これはそれほど難しいことではありません。彼らは両方とも、それが何をするかについてかなり上手です。ただし、この時点で、問題に遭遇しました。

XML オブジェクト自体に XML オブジェクトが含まれています。例えば:

<XMLObject>
    <OuterObject attributeOne="1" attributeTwo="2" attributeThree="&gt;">
        <InnerObject>&lt;NestedObject&gt;Blah&lt;/NestedObject&gt;</InnerObject>
    </OuterObject>
    <OuterObject attributeOne="11" attributeTwo="22" attributeThree="&lt;">
        <InnerObject>&lt;NestedObject&gt;Blah&lt;/NestedObject&gt;</InnerObject>
    </OuterObject>
    <OuterObject attributeOne="111" attributeTwo="222" attributeThree="3" />
<XMLObject>

XML ファイルを Jackson アノテーション付きの Java オブジェクトに読み込んだ瞬間、 と のすべてのインスタンスが、Woodstox によってそれぞれ と&lt;&gt;変換されます。オブジェクトを XML ファイルとして書き戻すと、<><&lt;>>

<XMLObject>
    <OuterObject attributeOne="1" attributeTwo="2" attributeThree=">">
        <InnerObject>&lt;NestedObject>Blah&lt;/NestedObject></InnerObject>
    </OuterObject>
    <OuterObject attributeOne="11" attributeTwo="22" attributeThree="&lt;">
        <InnerObject>&lt;NestedObject>Blah&lt;/NestedObject></InnerObject>
    </OuterObject>
    <OuterObject attributeOne="111" attributeTwo="222" attributeThree="3" />
<XMLObject>

ファイルを読み取ろうとしている私のメソッドの最も単純なバージョンは次のとおりです。

@RequestMapping("readXML")
public @ResponseBody CustomXMLObject readXML() throws Exception {
    File inputFile = new File(FILE_PATH);
    XmlMapper mapper = new XmlMapper();
    CustomXMLObject value = mapper.readValue(inputFile, CustomXMLObject .class);

    return value;
}

上記の例では、Jackson がアノテーションを付けた Java オブジェクトは次のようになります。

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class CustomXMLObject {
    @JacksonXmlProperty(isAttribute=true)
    private long attributeOne;
    @JacksonXmlProperty(isAttribute=true)
    private String attributeTwo;
    @JacksonXmlProperty(isAttribute=true)
    private String attributeThree;
    @JacksonXmlProperty(localName = "InnerObject")
    private String innerObject;


    public long getAttributeOne() {
        return attributeOne;
    }

    public void setAttributeOne(long attributeOne) {
        this.attributeOne = attributeOne;
    }

    public String getAttributeTwo() {
        return attributeTwo;
    }

    public void setAttributeTwo(String attributeTwo) {
        this.attributeTwo = attributeTwo;
    }

    public String getAttributeThree() {
        return attributeThree;
    }

    public void setAttributeThree(String attributeThree) {
        this.attributeThree = attributeThree;
    }

    public String getInnerObject() {
        return innerObject;
    }

    public void setInnerObject(String innerObject) {
        this.innerObject = innerObject;
    }
}

最後に、私の依存関係は次のようになります。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-jaxb-annotations</artifactId>
    <version>2.5.0</version>
</dependency>
<dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>2.8.4</version>
</dependency>
<dependency>
    <groupId>org.codehaus.woodstox</groupId>
    <artifactId>woodstox-core-asl</artifactId>
    <version>4.4.1</version>
</dependency>

これは、Jackson が Woodstox の BufferingXmlWriter を使用したために発生しているようです。この特定のライターは、これらの文字をインターセプトしてエンコードしますが、その決定を回避する方法はないようです。

private final void writeAttrValue(String value, int len) throws IOException {
    int inPtr = 0;
    char qchar = this.mEncQuoteChar;
    int highChar = this.mEncHighChar;

    while(true) {
        String ent = null;

        while(true) {
            if(inPtr >= len) {
                return;
            }

            char c = value.charAt(inPtr++);
            if(c <= 60) {
                if(c < 32) {
                    if(c == 13) {
                        if(this.mEscapeCR) {
                            break;
                        }
                    } else {
                        if(c == 10 || c == 9 || this.mXml11 && c != 0) {
                            break;
                        }

                        c = this.handleInvalidChar(c);
                    }
                } else {
                    if(c == qchar) {
                        ent = this.mEncQuoteEntity;
                        break;
                    }

                    if(c == 60) {
                        ent = "&lt;";
                        break;
                    }

                    if(c == 38) {
                        ent = "&amp;";
                        break;
                    }
                }
            } else if(c >= highChar) {
                break;
            }

            if(this.mOutputPtr >= this.mOutputBufLen) {
                this.flushBuffer();
            }

            this.mOutputBuffer[this.mOutputPtr++] = c;
        }

        if(ent != null) {
            this.writeRaw(ent);
        } else {
            this.writeAsEntity(value.charAt(inPtr - 1));
        }
    }
}

最後に問題を要約すると、XML ファイルが与えられました。その XML ファイルには、XML を壊さないようにエンコードされた ( および ) 記号 ( および ) を含む属性と要素が含まれてい<ます。Woodstox がファイルを読み取るとき、XML に含まれる実際の文字列を Java オブジェクトに渡す代わりに、文字をデコードします。書き込み時に、のみとして再エンコードされます。これは、Jackson が Woodstox の BufferingXmlWriter を使用しているため、これらの文字のエンコードを回避するように構成できないように思われるため発生しているようです。>&lt;&gt;<&lt;

その結果、私の質問は次のとおりです。

Woodstox XML リーダーを使用するように Jackson オブジェクトを構成して、XML ファイル内の文字をさらにエンコードせずに読み書きできるようにすることはできますか?それとも、自分のニーズに合わせて別のソリューションを検討する必要がありますか?

4

1 に答える 1