【问题标题】:Android Docx4J Error when reading in MS Word file: Didn't find class org.eclipse.persistence.oxm.NamespacePrefixMapper on path读取 MS Word 文件时出现 Android Docx4J 错误:在路径上找不到类 org.eclipse.persistence.oxm.NamespacePrefixMapper
【发布时间】:2020-02-14 11:19:59
【问题描述】:

我正在尝试使用 Docx4j 库来读取用户选择的 Word 文件的内容(尝试遵循 https://github.com/plutext/Docx4j4Android4 中的代码)但是,我收到以下错误当我阅读 MS Word 文件时:

W/System.err: log4j:ERROR Could not parse url [jar:file:/data/app/com.example.diffcheckertest-8hLouozp5QPE6U8NaxyKYA==/base.apk!/log4j.xml].
    javax.xml.parsers.ParserConfigurationException: No validating DocumentBuilder implementation available
        at org.apache.harmony.xml.parsers.DocumentBuilderFactoryImpl.newDocumentBuilder(DocumentBuilderFactoryImpl.java:61)
...
Process 20716 terminated.
    Caused by: java.lang.ClassNotFoundException: Didn't find class "org.eclipse.persistence.oxm.NamespacePrefixMapper" on path: DexPathList[[zip file "/data/app/com.example.diffcheckertest-8hLouozp5QPE6U8NaxyKYA==/base.apk"]

下面是MainActivity.kt 中我打开 MS Word 文档和发生错误的代码行(我已经导入了必要的实用程序):

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity

import org.apache.commons.lang3.StringUtils;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import java.io.BufferedReader
import java.io.InputStreamReader

class MainActivity : AppCompatActivity() {
    private var READ_IN_FILE:Int = 2; // Request code used when reading in a file


    // Asks a user to read in a file
    private fun chooseFile(view: View) {
        // Only the below specified mime types are allowed in the picker
        var selectFile = Intent(Intent.ACTION_GET_CONTENT)
        selectFile.type = "*/*"
        selectFile = Intent.createChooser(selectFile, "Choose a file")
        startActivityForResult(selectFile, READ_IN_FILE)
    }

    // After receiving a result for a launched activity...
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (requestCode == READ_IN_FILE) { // When a result has been received, check if it is the result for READ_IN_FILE
            if (resultCode == Activity.RESULT_OK) { // heck if the operation to retrieve the Activity's result is successful
                // Attempt to retrieve the file
                try {
                    var uri = data?.data // Retrieve the file's resource locator
                    var document = WordprocessingMLPackage.load(uri?.let { contentResolver.openInputStream(it) });
                    //var documentPart: MainDocumentPart = document.getMainDocumentPart();
                    Toast.makeText(this, "DiffChecker successfully read in the file :D", Toast.LENGTH_SHORT).show()
                } catch (e: Exception) { // If the app failed to attempt to retrieve the error file, throw an error alert
                    println("Exception: " + e.toString());
                    Toast.makeText(this, "Sorry, but there was an error reading in the file", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<Button>(R.id.file1).setOnClickListener(::chooseFile);
    }
}

下面是我的build.gradle 代码(应用级):

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.example.diffcheckertest"
        minSdkVersion 22
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/ASL2.0'
        exclude("META-INF/*.kotlin_module")
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation files('libs/activation.jar')
    implementation files('libs/additionnal.jar')
    implementation files('libs/awt-bastardised-17v8.jar')
    implementation files('libs/istack-commons-runtime-3.0.4-SNAPSHOT.jar')
    implementation files('libs/jaxb-core-2.3.0-SNAPSHOT-ANDROID.jar')
    implementation files('libs/jaxb-runtime-2.3.0-SNAPSHOT-ANDROID.jar')

    //implementation files('libs/commons-lang3-3.7.jar')
    //implementation files('libs/commons-text-1.2.jar')
    implementation 'javax.xml.stream:stax-api:1.0-2'
    implementation 'com.fasterxml:aalto-xml:1.0.0'

    implementation files('libs/docx4j-6.1.1-SNAPSHOT-shaded.jar')

}

构建是我的build.gradle 代码(项目级):

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext.kotlin_version = '1.3.61'
    repositories {
        google()
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()

    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

【问题讨论】:

  • @JasonPlutext 我尝试将 stax 和 aalto 添加到我的 build.gradle 但不幸的是它仍然无法正常工作。作为 docx4j 项目的维护者,您是否有一个完整的示例 Android 应用程序(当前)使用 docx4j 读取 MS-Word 文件的内容?
  • @JasonPlutext 我知道您有一个 GitHub 存储库,用于演示如何在 Android 应用程序中使用 docx4j,但这是在 Java 中。你有可以运行的 Kotlin 版本吗?
  • @JasonPlutext Android 示例展示了一个创建 .docx 的 Android 应用程序。您能否提供一个 Android 应用读取用户选择的 .docx 的示例?

标签: android kotlin ms-word docx docx4j


【解决方案1】:

在没有 javax.xml.bind:jaxb-api:2.2.12 依赖项的情况下,您的项目如何工作?它应该首先抛出java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/xml/bind/JAXBContext;

Android 不支持开箱即用的 JAXB,您必须显式添加依赖项。

implementation 'javax.xml.bind:jaxb-api:2.2.12'

我决定创建一个新项目并从头开始一切,而不是尝试您的 gradle 设置。幸运的是,我可以毫无问题地运行和加载任何 docx 文件。

download my sample repository 并在您的系统中尝试。

【讨论】:

    【解决方案2】:

    使用自 Android 4.4(API 级别 19)起可用的 SAF(存储访问框架)选择文件:

    // Asks a user to read in a file
    private fun chooseFile(view: View) {
        // Only the below specified mime types are allowed in the picker
        var selectFile = Intent(Intent.ACTION_OPEN_DOCUMENT)
        selectFile.type = "*/*"
        selectFile.addCategory(Intent.CATEGORY_OPENABLE)
        selectFile = Intent.createChooser(selectFile, "Choose a file")
        startActivityForResult(selectFile, READ_IN_FILE)
    }
    

    为了防止ClassNotFoundException"org.eclipse.persistence.oxm.NamespacePrefixMapper" 将以下行添加到您的 gradle 文件依赖项:

    implementation 'org.eclipse.persistence:eclipselink:2.7.6'
    

    为了防止重复类错误,您可以排除重复类:

    implementation ('org.eclipse.persistence:eclipselink:2.7.6'){
              exclude group: 'javax.persistence.spi', module: 'ProviderUtil'
              exclude group: 'javax.persistence', module: 'Access'
    }
    

    How to run JAXB in Android

    【讨论】:

    • 我收到以下错误:在模块 eclipselink-2.5.0.jar (org.eclipse.persistence:eclipselink:2.5.0) 和 javax.persistence 中发现重复的类 javax.persistence.spi.ProviderUtil -2.1.0.jar (org.eclipse.persistence:javax.persistence:2.1.0)
    • 尽管将版本更改为 2.7.6,我仍然收到以下错误:在模块 eclipselink-2.7.6.jar (org.eclipse.persistence:eclipselink: 2.7.6) 和 jakarta.persistence-2.2.3.jar (org.eclipse.persistence:jakarta.persistence:2.2.3)
    • @AdamLee 你能像我更新的答案那样排除重复的类吗?
    • @Bahman 即使使用排除语句,我仍然会遇到相同的重复类错误。需要明确的是,我的重复类错误不仅仅是 javax.persistence.Access 和 javax.persistence.spi.ProviderUtil,还有几十个重复类错误都来自 javax.persistence 和 javax.persistence.spi。但是,即使我尝试排除整个两个组(不指定模块),我仍然很遗憾有重复的类错误。
    • @AdamLee 使用docx4j的示例docx阅读器:github.com/plutext/AndroidDocxToHtml
    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-06
    • 2022-01-19
    相关资源
    最近更新 更多