استخراج متن از اسناد MS Word در جاوا

استخراج متن از اسناد Word اغلب در سناریوهای مختلف انجام می شود. به عنوان مثال، برای تجزیه و تحلیل متن، استخراج بخش های خاصی از یک سند و ترکیب آنها در یک سند واحد و غیره. در این مقاله نحوه استخراج متن از اسناد ورد به صورت برنامه نویسی در جاوا را خواهید آموخت. علاوه بر این، نحوه استخراج محتوا بین عناصر خاص مانند پاراگراف ها، جداول و غیره را به صورت پویا توضیح خواهیم داد.

کتابخانه جاوا برای استخراج متن از اسناد Word

Aspose.Words for Java یک کتابخانه قدرتمند است که به شما امکان می دهد اسناد MS Word را از ابتدا ایجاد کنید. علاوه بر این، به شما امکان می دهد اسناد Word موجود را برای رمزگذاری، تبدیل، استخراج متن و غیره دستکاری کنید. ما از این کتابخانه برای استخراج متن از اسناد Word DOCX یا DOC استفاده خواهیم کرد. می‌توانید JAR API را دانلود یا با استفاده از تنظیمات Maven زیر نصب کنید.

<repository>
    <id>AsposeJavaAPI</id>
    <name>Aspose Java API</name>
    <url>https://repository.aspose.com/repo/</url>
</repository>
<dependency>
    <groupId>com.aspose</groupId>
    <artifactId>aspose-words</artifactId>
    <version>22.6</version>
    <type>pom</type>
</dependency>

استخراج متن در Word DOC/DOCX در جاوا

یک سند MS Word از عناصر مختلفی تشکیل شده است که شامل پاراگراف ها، جداول، تصاویر و غیره می شود. بنابراین، الزامات استخراج متن می تواند از سناریویی به سناریوی دیگر متفاوت باشد. به عنوان مثال، ممکن است لازم باشد متنی را بین پاراگراف ها، نشانک ها، نظرات و غیره استخراج کنید.

هر نوع عنصر در Word DOC/DOCX به عنوان یک گره نشان داده می شود. بنابراین، برای پردازش یک سند، باید با گره ها بازی کنید. پس بیایید شروع کنیم و نحوه استخراج متن از اسناد Word را در سناریوهای مختلف ببینیم.

متن را از یک Word DOC در جاوا استخراج کنید

در این بخش قصد داریم یک استخراج کننده متن جاوا برای اسناد Word پیاده سازی کنیم و گردش کار استخراج متن به صورت زیر خواهد بود:

  • ابتدا گره هایی را که می خواهیم در فرآیند استخراج متن قرار دهیم را تعریف می کنیم.
  • سپس، محتوا را بین گره های مشخص شده (شامل یا حذف گره های شروع و پایان) استخراج می کنیم.
  • در نهایت، ما از کلون گره های استخراج شده استفاده می کنیم، به عنوان مثال برای ایجاد یک سند Word جدید متشکل از محتوای استخراج شده.

اکنون متدی به نام extractContent می نویسیم که گره ها و برخی پارامترهای دیگر را برای انجام استخراج متن به آن پاس می دهیم. این روش سند را تجزیه و گره ها را شبیه سازی می کند. در زیر پارامترهایی هستند که به این متد ارسال می کنیم.

  1. startNode و endNode به ترتیب به عنوان نقاط شروع و پایان برای استخراج محتوا. این گره‌ها می‌توانند هر دو سطح بلوک (پاراگراف، جدول) یا سطح درون خطی (به عنوان مثال Run، FieldStart، BookmarkStart و غیره) باشند.
    1. برای ارسال یک فیلد باید شی FieldStart مربوطه را ارسال کنید.
    2. برای ارسال نشانک ها، گره های BookmarkStart و BookmarkEnd باید ارسال شوند.
    3. برای نظرات، گره های CommentRangeStart و CommentRangeEnd باید استفاده شوند.
  2. isInclusive مشخص می کند که آیا نشانگرها در استخراج گنجانده شده اند یا خیر. اگر این گزینه روی false تنظیم شود و همان گره یا گره های متوالی ارسال شود، یک لیست خالی برگردانده می شود.

در زیر پیاده سازی کامل متد extractContent است که محتوا را بین گره هایی که ارسال می شود استخراج می کند.

// برای نمونه‌های کامل و فایل‌های داده، لطفاً به https://github.com/aspose-words/Aspose.Words-for-Java بروید
public static ArrayList extractContent(Node startNode, Node endNode, boolean isInclusive) throws Exception {
    // ابتدا بررسی کنید که گره های ارسال شده به این روش برای استفاده معتبر هستند.
    verifyParameterNodes(startNode, endNode);

    // یک لیست برای ذخیره گره های استخراج شده ایجاد کنید.
    ArrayList nodes = new ArrayList();

    // یک رکورد از گره های اصلی ارسال شده به این روش نگه دارید تا در صورت نیاز بتوانیم گره های نشانگر را تقسیم کنیم.
    Node originalStartNode = startNode;
    Node originalEndNode = endNode;

    // استخراج محتوا بر اساس گره های سطح بلوک (پاراگراف ها و جداول). از میان گره های والد عبور کنید تا آنها را پیدا کنید.
    // بسته به خطی بودن گره های نشانگر، محتوای گره های اول و آخر را تقسیم می کنیم
    while (startNode.getParentNode().getNodeType() != NodeType.BODY)
        startNode = startNode.getParentNode();

    while (endNode.getParentNode().getNodeType() != NodeType.BODY)
        endNode = endNode.getParentNode();

    boolean isExtracting = true;
    boolean isStartingNode = true;
    boolean isEndingNode;
    // گره فعلی که از سند استخراج می کنیم.
    Node currNode = startNode;

    // شروع به استخراج محتوا کنید. تمام گره های سطح بلوک را پردازش کنید و به طور خاص اولین و آخرین گره ها را در صورت نیاز تقسیم کنید تا قالب بندی پاراگراف حفظ شود.
    // این روش کمی پیچیده‌تر از استخراج‌کننده معمولی است، زیرا باید در استخراج با استفاده از گره‌های درون خطی، فیلدها، نشانک‌ها و غیره فاکتور بگیریم تا واقعاً مفید باشد.
    while (isExtracting) {
        // برای بدست آوردن یک کپی، گره فعلی و فرزندان آن را شبیه سازی کنید.
        /*System.out.println(currNode.getNodeType());
        if(currNode.getNodeType() == NodeType.EDITABLE_RANGE_START
                || currNode.getNodeType() == NodeType.EDITABLE_RANGE_END)
        {
            currNode = currNode.nextPreOrder(currNode.getDocument());
        }*/
        System.out.println(currNode);
        System.out.println(endNode);

        CompositeNode cloneNode = null;
        ///cloneNode = (CompositeNode) currNode.deepClone(true);

        Node inlineNode = null;
        if(currNode.isComposite())
        {
            cloneNode = (CompositeNode) currNode.deepClone(true);
        }
        else
        {
            if(currNode.getNodeType() == NodeType.BOOKMARK_END)
            {
                Paragraph paragraph = new Paragraph(currNode.getDocument());
                paragraph.getChildNodes().add(currNode.deepClone(true));
                cloneNode = (CompositeNode)paragraph.deepClone(true);
            }
        }

        isEndingNode = currNode.equals(endNode);

        if (isStartingNode || isEndingNode) {
            // ما باید هر نشانگر را جداگانه پردازش کنیم، بنابراین آن را به یک روش جداگانه منتقل کنیم.
            if (isStartingNode) {
                processMarker(cloneNode, nodes, originalStartNode, isInclusive, isStartingNode, isEndingNode);
                isStartingNode = false;
            }

            // شرطی باید جدا باشد زیرا نشانگرهای شروع و پایان سطح بلوک ممکن است یک گره باشند.
            if (isEndingNode) {
                processMarker(cloneNode, nodes, originalEndNode, isInclusive, isStartingNode, isEndingNode);
                isExtracting = false;
            }
        } else
            // Node یک نشانگر شروع یا پایان نیست، به سادگی کپی را به لیست اضافه کنید.
            nodes.add(cloneNode);

        // به گره بعدی بروید و آن را استخراج کنید. اگر گره بعدی تهی باشد، به این معنی است که بقیه محتوا در بخش دیگری یافت می شود.
        if (currNode.getNextSibling() == null && isExtracting) {
            // به بخش بعدی بروید.
            Section nextSection = (Section) currNode.getAncestor(NodeType.SECTION).getNextSibling();
            currNode = nextSection.getBody().getFirstChild();
        } else {
            // به گره بعدی در بدنه بروید.
            currNode = currNode.getNextSibling();
        }
    }

    // گره ها را بین نشانگرهای گره برگردانید.
    return nodes;
}

برخی از روش های کمکی نیز توسط متد extractContent برای انجام عملیات استخراج متن مورد نیاز است که در زیر آورده شده است.

/**
 * درست بودن پارامترهای ورودی را بررسی می کند و می تواند مورد استفاده قرار گیرد. استثنا می اندازد
 * اگر مشکلی وجود دارد
 */
private static void verifyParameterNodes(Node startNode, Node endNode) throws Exception {
	// ترتیب انجام این بررسی ها مهم است.
	if (startNode == null)
		throw new IllegalArgumentException("Start node cannot be null");
	if (endNode == null)
		throw new IllegalArgumentException("End node cannot be null");

	if (!startNode.getDocument().equals(endNode.getDocument()))
		throw new IllegalArgumentException("Start node and end node must belong to the same document");

	if (startNode.getAncestor(NodeType.BODY) == null || endNode.getAncestor(NodeType.BODY) == null)
		throw new IllegalArgumentException("Start node and end node must be a child or descendant of a body");

	// بررسی کنید که گره پایانی بعد از گره شروع در درخت DOM باشد
	// ابتدا بررسی کنید که آیا آنها در بخش های مختلف هستند یا خیر، سپس اگر بررسی نمی شوند
	// موقعیت آنها در بدنه همان قسمتی که در آن قرار دارند.
	Section startSection = (Section) startNode.getAncestor(NodeType.SECTION);
	Section endSection = (Section) endNode.getAncestor(NodeType.SECTION);

	int startIndex = startSection.getParentNode().indexOf(startSection);
	int endIndex = endSection.getParentNode().indexOf(endSection);

	if (startIndex == endIndex) {
		if (startSection.getBody().indexOf(startNode) > endSection.getBody().indexOf(endNode))
			throw new IllegalArgumentException("The end node must be after the start node in the body");
	} else if (startIndex > endIndex)
		throw new IllegalArgumentException("The section of end node must be after the section start node");
}

/**
 * بررسی می کند که آیا یک گره ارسال شده یک گره درون خطی است یا خیر.
 */
private static boolean isInline(Node node) throws Exception {
	// تست کنید که آیا گره از نود پاراگراف یا جدول است و همچنین a نیست
	// پاراگراف یا جدول یک پاراگراف در داخل یک کلاس کامنت که از آن جدا می شود
	// یک پاراف ممکن است.
	return ((node.getAncestor(NodeType.PARAGRAPH) != null || node.getAncestor(NodeType.TABLE) != null)
			&& !(node.getNodeType() == NodeType.PARAGRAPH || node.getNodeType() == NodeType.TABLE));
}

/**
 * بسته به اینکه محتوای قبل یا بعد از نشانگر در گره کلون شده را حذف می کند
 * بر روی نوع نشانگر
 */
private static void processMarker(CompositeNode cloneNode, ArrayList nodes, Node node, boolean isInclusive,
		boolean isStartMarker, boolean isEndMarker) throws Exception {
	// اگر با یک گره سطح بلوک سروکار داریم، فقط ببینید که آیا باید شامل شود یا خیر
	// و آن را به لیست اضافه کنید.
	if (!isInline(node)) {
		// اگر نشانگرها همان گره هستند، گره را دوبار اضافه نکنید
		if (!(isStartMarker && isEndMarker)) {
			if (isInclusive)
				nodes.add(cloneNode);
		}
		return;
	}

	// اگر یک نشانگر یک گره FieldStart است، بررسی کنید که آیا قرار است شامل شود یا خیر.
	// ما برای سادگی فرض می کنیم که FieldStart و FieldEnd به صورت یکسان ظاهر می شوند
	// پاراگراف
	if (node.getNodeType() == NodeType.FIELD_START) {
		// اگر نشانگر یک گره شروع است و گنجانده نشده است، به انتهای آن بروید
		// میدان
		// اگر نشانگر یک گره انتهایی است و قرار است در آن گنجانده شود، به انتها بروید
		// فیلد بنابراین فیلد حذف نخواهد شد.
		if ((isStartMarker && !isInclusive) || (!isStartMarker && isInclusive)) {
			while (node.getNextSibling() != null && node.getNodeType() != NodeType.FIELD_END)
				node = node.getNextSibling();

		}
	}

	// اگر هر یک از نشانگرها بخشی از یک نظر است، باید خود نظر را نیز لحاظ کنیم
	// باید نشانگر را به سمت نظر حرکت دهید
	// گره بعد از گره CommentRangeEnd پیدا شد.
	if (node.getNodeType() == NodeType.COMMENT_RANGE_END) {
		while (node.getNextSibling() != null && node.getNodeType() != NodeType.COMMENT)
			node = node.getNextSibling();

	}

	// گره مربوطه را در گره کلون شده خود با شاخص پیدا کنید و آن را برگردانید.
	// اگر گره شروع و پایان یکسان باشد برخی از گره های فرزند ممکن است قبلا داشته باشند
	// حذف شده است. کم کنید
	// تفاوت برای بدست آوردن شاخص مناسب
	int indexDiff = node.getParentNode().getChildNodes().getCount() - cloneNode.getChildNodes().getCount();

	// تعداد گره های کودک یکسان است.
	if (indexDiff == 0)
		node = cloneNode.getChildNodes().get(node.getParentNode().indexOf(node));
	else
		node = cloneNode.getChildNodes().get(node.getParentNode().indexOf(node) - indexDiff);

	// گره ها را تا/از نشانگر بردارید.
	boolean isSkip;
	boolean isProcessing = true;
	boolean isRemoving = isStartMarker;
	Node nextNode = cloneNode.getFirstChild();

	while (isProcessing && nextNode != null) {
		Node currentNode = nextNode;
		isSkip = false;

		if (currentNode.equals(node)) {
			if (isStartMarker) {
				isProcessing = false;
				if (isInclusive)
					isRemoving = false;
			} else {
				isRemoving = true;
				if (isInclusive)
					isSkip = true;
			}
		}

		nextNode = nextNode.getNextSibling();
		if (isRemoving && !isSkip)
			currentNode.remove();
	}

	// پس از پردازش، گره مرکب ممکن است خالی شود. اگر دارد شامل نمی شود
	// آی تی.
	if (!(isStartMarker && isEndMarker)) {
		if (cloneNode.hasChildNodes())
			nodes.add(cloneNode);
	}
}

public static Document generateDocument(Document srcDoc, ArrayList nodes) throws Exception {

	// یک سند خالی ایجاد کنید.
	Document dstDoc = new Document();
	// پاراگراف اول را از سند خالی حذف کنید.
	dstDoc.getFirstSection().getBody().removeAllChildren();

	// هر گره را از لیست به سند جدید وارد کنید. اصل را نگه دارید
	// قالب بندی گره
	NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.KEEP_SOURCE_FORMATTING);

	for (Node node : (Iterable<Node>) nodes) {
		Node importNode = importer.importNode(node, true);
		dstDoc.getFirstSection().getBody().appendChild(importNode);
	}

	// سند ایجاد شده را برگردانید.
	return dstDoc;
}

اکنون ما آماده ایم که از این روش ها استفاده کرده و متن را از یک سند Word استخراج کنیم.

استخراج متن جاوا بین پاراگراف ها در Word DOC

بیایید نحوه استخراج محتوا بین دو پاراگراف در یک سند Word DOCX را ببینیم. در ادامه مراحل انجام این عملیات در جاوا آمده است.

  • ابتدا سند Word را با استفاده از کلاس Document بارگذاری کنید.
  • با استفاده از روش Document.getFirstSection().getChild(NodeType.PARAGRAPH، int، bool)، مرجع پاراگراف های شروع و پایان را به دو شیء دریافت کنید.
  • برای استخراج گره ها در یک شی، متد extractContent(startPara، endPara، true) را فراخوانی کنید.
  • برای ایجاد سند متشکل از محتوای استخراج شده، روش کمکی generateDocument(Document, extractedNodes) را فراخوانی کنید.
  • در نهایت، سند برگشتی را با استفاده از روش Document.save(String) ذخیره کنید.

نمونه کد زیر نحوه استخراج متن بین پاراگراف های 7 و 11 را در Word DOCX در جاوا نشان می دهد.

// بارگذاری سند
Document doc = new Document("TestFile.doc");

// گره ها را جمع آوری کنید. روش GetChild از شاخص مبتنی بر 0 استفاده می کند
Paragraph startPara = (Paragraph) doc.getFirstSection().getChild(NodeType.PARAGRAPH, 6, true);
Paragraph endPara = (Paragraph) doc.getFirstSection().getChild(NodeType.PARAGRAPH, 10, true);
// محتوای بین این گره ها را در سند استخراج کنید. اینها را شامل شود
// نشانگرها در استخراج
ArrayList extractedNodes = extractContent(startPara, endPara, true);

// محتوا را در یک سند جداگانه جدید قرار دهید و آن را در دیسک ذخیره کنید.
Document dstDoc = generateDocument(doc, extractedNodes);
dstDoc.save("output.doc");

استخراج متن جاوا از DOC - بین انواع مختلف گره ها

همچنین می توانید محتوا را بین انواع مختلف گره ها استخراج کنید. برای نمایش، بیایید محتوا را بین یک پاراگراف و یک جدول استخراج کنیم و آن را در یک سند جدید Word ذخیره کنیم. در زیر مراحل استخراج متن بین گره های مختلف در یک سند Word در جاوا آمده است.

  • سند Word را با استفاده از کلاس Document بارگیری کنید.
  • با استفاده از روش Document.getFirstSection().getChild(NodeType، int، bool)، مرجع گره های شروع و پایان را به دو شیء دریافت کنید.
  • برای استخراج گره ها در یک شی، متد extractContent(startPara، endPara، true) را فراخوانی کنید.
  • برای ایجاد سند متشکل از محتوای استخراج شده، روش کمکی generateDocument(Document, extractedNodes) را فراخوانی کنید.
  • سند برگشتی را با استفاده از روش Document.save(String) ذخیره کنید.

نمونه کد زیر نحوه استخراج متن بین پاراگراف و جدول در DOCX با استفاده از جاوا را نشان می دهد.

// اسناد را بارگیری کنید
Document doc = new Document("TestFile.doc");

// دریافت مرجع پاراگراف شروع
Paragraph startPara = (Paragraph) doc.getLastSection().getChild(NodeType.PARAGRAPH, 2, true);
Table endTable = (Table) doc.getLastSection().getChild(NodeType.TABLE, 0, true);

// محتوای بین این گره ها را در سند استخراج کنید. این نشانگرها را در استخراج قرار دهید.
ArrayList extractedNodes = extractContent(startPara, endTable, true);

// اجازه می دهد تا آرایه را معکوس کنیم تا درج مجدد محتوا در سند آسان تر شود.
Collections.reverse(extractedNodes);

while (extractedNodes.size() > 0) {
    // آخرین گره را از لیست معکوس وارد کنید
    endTable.getParentNode().insertAfter((Node) extractedNodes.get(0), endTable);
    // پس از درج این گره را از لیست حذف کنید.
    extractedNodes.remove(0);
}

// سند تولید شده را روی دیسک ذخیره کنید.
doc.save("output.doc");

جاوا استخراج متن از DOCX - بین پاراگراف ها بر اساس سبک

اکنون بیایید نحوه استخراج محتوا بین پاراگراف ها را بر اساس سبک ها بررسی کنیم. برای نمایش، ما بین اولین “هدینگ 1” و “هدینگ 3” اول در سند ورد، محتوایی را استخراج می کنیم. مراحل زیر نحوه دستیابی به این امر در جاوا را نشان می دهد.

  • ابتدا سند Word را با استفاده از کلاس Document بارگذاری کنید.
  • سپس با استفاده از روش کمکی paragraphsByStyleName (Document, “Heading 1”) پاراگراف ها را در یک شی استخراج کنید.
  • با استفاده از روش کمکی paragraphsByStyleName (Document, “Heading 3”) پاراگراف ها را در یک شی دیگر استخراج کنید.
  • متد extractContent(startPara, endPara, true) را فراخوانی کنید و عناصر اول را در هر دو آرایه پاراگراف به عنوان پارامترهای اول و دوم ارسال کنید.
  • برای ایجاد سند متشکل از محتوای استخراج شده، روش کمکی generateDocument(Document, extractedNodes) را فراخوانی کنید.
  • در نهایت، سند برگشتی را با استفاده از روش Document.save(String) ذخیره کنید.

نمونه کد زیر نحوه استخراج محتوا بین پاراگراف ها را بر اساس سبک ها نشان می دهد.

// بارگذاری سند
Document doc = new Document(dataDir + "TestFile.doc");

// فهرستی از پاراگراف ها را با استفاده از سبک های عنوان مربوطه جمع آوری کنید.
ArrayList parasStyleHeading1 = paragraphsByStyleName(doc, "Heading 1");
ArrayList parasStyleHeading3 = paragraphsByStyleName(doc, "Heading 3");

// از اولین نمونه پاراگراف ها با آن سبک ها استفاده کنید.
Node startPara1 = (Node) parasStyleHeading1.get(0);
Node endPara1 = (Node) parasStyleHeading3.get(0);

// محتوای بین این گره ها را در سند استخراج کنید. این نشانگرها را در استخراج وارد نکنید.
ArrayList extractedNodes = extractContent(startPara1, endPara1, false);

// محتوا را در یک سند جداگانه جدید قرار دهید و آن را در دیسک ذخیره کنید.
Document dstDoc = generateDocument(doc, extractedNodes);
dstDoc.save("output.doc");

استخراج متن جاوا ورد - ادامه مطلب

می توانید سناریوهای دیگر استخراج متن از اسناد Word را با استفاده از [این 5 مقاله مستند بررسی کنید.

Java API برای استخراج متن از DOC/DOCX - یک مجوز رایگان دریافت کنید

می توانید برای استفاده از Aspose.Words برای جاوا بدون محدودیت ارزیابی، مجوز موقت دریافت کنید.

نتیجه

در این مقاله نحوه استخراج متن از MS Word DOC DOCX در جاوا را یاد گرفتید. علاوه بر این، نحوه استخراج محتوا بین انواع مشابه یا متفاوت گره ها در یک سند Word را به صورت برنامه نویسی دیده اید. بنابراین، می توانید استخراج کننده متن MS Word خود را در جاوا بسازید. علاوه بر این، می‌توانید سایر ویژگی‌های Aspose.Words برای جاوا را با استفاده از مستندات کاوش کنید. در صورت داشتن هرگونه سوال، از طریق [تالار گفتمان8 ما را در جریان بگذارید.

همچنین ببینید