Java'daki MS Word Belgelerinden Metin Çıkarma

Word belgelerinden metin çıkarma genellikle farklı senaryolarda gerçekleştirilir. Örneğin, metni analiz etmek, bir belgenin belirli bölümlerini çıkarmak ve bunları tek bir belgede birleştirmek vb. Bu makalede, Java’da programlı olarak Word belgelerinden metin çıkarmayı öğreneceksiniz. Ayrıca, içeriğin paragraflar, tablolar vb. belirli öğeler arasında dinamik olarak nasıl çıkarılacağını ele alacağız.

Word Belgelerinden Metin Çıkarmak için Java Kitaplığı

Aspose.Words for Java, MS Word belgelerini sıfırdan oluşturmanıza olanak tanıyan güçlü bir kitaplıktır. Ayrıca, mevcut Word belgelerini şifreleme, dönüştürme, metin çıkarma vb. için değiştirmenize olanak tanır. Bu kitaplığı, Word DOCX veya DOC belgelerinden metin çıkarmak için kullanacağız. API’nin JAR’ını indirebilir veya aşağıdaki Maven yapılandırmalarını kullanarak kurabilirsiniz.

<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>

Java’da Word DOC/DOCX’te Metin Çıkarma

Bir MS Word belgesi, paragraflar, tablolar, resimler vb. içeren çeşitli öğelerden oluşur. Bu nedenle, metin çıkarma gereksinimleri bir senaryodan diğerine değişebilir. Örneğin, paragraflar, yer imleri, yorumlar vb. arasında metin ayıklamanız gerekebilir.

Word DOC/DOCX’teki her öğe türü bir düğüm olarak temsil edilir. Bu nedenle, bir belgeyi işlemek için düğümlerle oynamanız gerekecek. Öyleyse başlayalım ve farklı senaryolarda Word belgelerinden nasıl metin çıkarılacağını görelim.

Java’daki bir Word DOC’tan Metin Çıkarma

Bu bölümde, Word belgeleri için bir Java metin çıkarıcı uygulayacağız ve metin çıkarmanın iş akışı aşağıdaki gibi olacaktır:

  • İlk olarak, metin çıkarma işlemine dahil etmek istediğimiz düğümleri tanımlayacağız.
  • Ardından, belirtilen düğümler arasındaki içeriği çıkaracağız (başlangıç ve bitiş düğümleri dahil veya hariç).
  • Son olarak, örneğin çıkarılan içerikten oluşan yeni bir Word belgesi oluşturmak için çıkarılan düğümlerin klonunu kullanacağız.

Şimdi, metin çıkarımını gerçekleştirmek için düğümleri ve diğer bazı parametreleri geçireceğimiz, extractContent adında bir metot yazalım. Bu yöntem belgeyi ayrıştırır ve düğümleri klonlar. Bu metoda ileteceğimiz parametreler aşağıdadır.

  1. içeriğin çıkarılması için sırasıyla başlangıç ve bitiş noktaları olarak startNode ve endNode. Bunlar hem blok düzeyinde (Paragraf , Tablo) hem de satır içi düzeyde (örn. Çalıştır, FieldStart, BookmarkStart vb.) düğümler olabilir.
    1. Bir alanı geçmek için ilgili FieldStart nesnesini geçmelisiniz.
    2. Yer imlerini geçirmek için BookmarkStart ve BookmarkEnd düğümleri geçilmelidir.
    3. Yorumlar için, CommentRangeStart ve CommentRangeEnd düğümleri kullanılmalıdır.
  2. isInclusive, belirteçlerin ayıklamaya dahil edilip edilmediğini tanımlar. Bu seçenek false olarak ayarlanırsa ve aynı düğüm veya ardışık düğümler geçirilirse boş bir liste döndürülür.

Aşağıda, iletilen düğümler arasındaki içeriği çıkaran extractContent yönteminin tam uygulaması yer almaktadır.

// Eksiksiz örnekler ve veri dosyaları için lütfen https://github.com/aspose-words/Aspose.Words-for-Java adresine gidin.
public static ArrayList extractContent(Node startNode, Node endNode, boolean isInclusive) throws Exception {
    // Öncelikle bu metoda iletilen düğümlerin kullanım için geçerli olup olmadığını kontrol edin.
    verifyParameterNodes(startNode, endNode);

    // Ayıklanan düğümleri depolamak için bir liste oluşturun.
    ArrayList nodes = new ArrayList();

    // Gerekirse işaretçi düğümleri ayırabilmemiz için bu yönteme iletilen orijinal düğümlerin kaydını tutun.
    Node originalStartNode = startNode;
    Node originalEndNode = endNode;

    // Blok düzeyinde düğümlere (paragraflar ve tablolar) dayalı olarak içeriği ayıklayın. Onları bulmak için üst düğümler arasında dolaşın.
    // İşaretleyici düğümlerin satır içi olup olmadığına bağlı olarak ilk ve son düğümlerin içeriğini böleceğiz
    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;
    // Belgeden çıkardığımız geçerli düğüm.
    Node currNode = startNode;

    // İçeriği çıkarmaya başlayın. Tüm blok seviyesindeki düğümleri işleyin ve paragraf biçimlendirmesinin korunması için gerektiğinde özellikle ilk ve son düğümleri ayırın.
    // Yöntem, normal bir çıkarıcıdan biraz daha karmaşıktır, çünkü gerçekten kullanışlı hale getirmek için satır içi düğümleri, alanları, yer imlerini vb. kullanarak ayıklamayı hesaba katmamız gerekir.
    while (isExtracting) {
        // Bir kopya elde etmek için geçerli düğümü ve alt öğelerini klonlayın.
        /*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) {
            // Her işaretçiyi ayrı ayrı işlememiz gerekiyor, bu yüzden onu ayrı bir yönteme aktarın.
            if (isStartingNode) {
                processMarker(cloneNode, nodes, originalStartNode, isInclusive, isStartingNode, isEndingNode);
                isStartingNode = false;
            }

            // Koşullu, blok düzeyi başlangıç ve bitiş işaretleri aynı düğüm olabileceğinden ayrı olması gerekir.
            if (isEndingNode) {
                processMarker(cloneNode, nodes, originalEndNode, isInclusive, isStartingNode, isEndingNode);
                isExtracting = false;
            }
        } else
            // Düğüm bir başlangıç veya bitiş işaretçisi değildir, kopyayı listeye eklemeniz yeterlidir.
            nodes.add(cloneNode);

        // Bir sonraki düğüme geçin ve ayıklayın. Bir sonraki düğüm boşsa, bu, içeriğin geri kalanının farklı bir bölümde bulunduğu anlamına gelir.
        if (currNode.getNextSibling() == null && isExtracting) {
            // Sonraki bölüme geçin.
            Section nextSection = (Section) currNode.getAncestor(NodeType.SECTION).getNextSibling();
            currNode = nextSection.getBody().getFirstChild();
        } else {
            // Vücuttaki bir sonraki düğüme git.
            currNode = currNode.getNextSibling();
        }
    }

    // Düğüm işaretçileri arasındaki düğümleri döndürün.
    return nodes;
}

ExtractContent yöntemi tarafından metin çıkarma işlemini gerçekleştirmek için aşağıda verilen bazı yardımcı yöntemler de gereklidir.

/**
 * Giriş parametrelerinin doğru olup olmadığını ve kullanılabilir olup olmadığını kontrol eder. Bir istisna atar
 * herhangi bir sorun varsa.
 */
private static void verifyParameterNodes(Node startNode, Node endNode) throws Exception {
	// Bu kontrollerin yapılma sırası önemlidir.
	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");

	// Bitiş düğümünün, DOM ağacındaki başlangıç düğümünden sonra olduğunu kontrol edin
	// Önce farklı bölümlerde olup olmadıklarını kontrol edin, sonra kontrol edip etmediklerini kontrol edin.
	// bulundukları bölümün gövdesindeki konumları.
	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");
}

/**
 * Geçilen bir düğümün satır içi düğüm olup olmadığını kontrol eder.
 */
private static boolean isInline(Node node) throws Exception {
	// Düğümün bir Paragraf veya Tablo düğümünün soyundan olup olmadığını ve aynı zamanda bir
	// paragraf veya tablo bir yorum sınıfının içindeki bir paragraftır.
	// bir paragraf mümkündür.
	return ((node.getAncestor(NodeType.PARAGRAPH) != null || node.getAncestor(NodeType.TABLE) != null)
			&& !(node.getNodeType() == NodeType.PARAGRAPH || node.getNodeType() == NodeType.TABLE));
}

/**
 * bağlı olarak klonlanmış düğümdeki işaretçiden önceki veya sonraki içeriği kaldırır.
 * işaretleyici türü üzerinde.
 */
private static void processMarker(CompositeNode cloneNode, ArrayList nodes, Node node, boolean isInclusive,
		boolean isStartMarker, boolean isEndMarker) throws Exception {
	// Bir blok seviyesi düğümü ile uğraşıyorsak, dahil edilmesi gerekip gerekmediğine bakın.
	// ve listeye ekleyin.
	if (!isInline(node)) {
		// İşaretçiler aynı düğüm ise, düğümü iki kez eklemeyin
		if (!(isStartMarker && isEndMarker)) {
			if (isInclusive)
				nodes.add(cloneNode);
		}
		return;
	}

	// Bir işaretçi bir FieldStart düğümüyse, dahil edilip edilmeyeceğini kontrol edin.
	// Basit olması için FieldStart ve FieldEnd'in aynı şekilde göründüğünü varsayıyoruz.
	// paragraf.
	if (node.getNodeType() == NodeType.FIELD_START) {
		// İşaretçi bir başlangıç düğümüyse ve dahil edilmemişse, o zaman sonuna atla
		// alan.
		// İşaretçi bir bitiş düğümüyse ve dahil edilecekse sona doğru ilerleyin
		// alan, böylece alan kaldırılmayacaktır.
		if ((isStartMarker && !isInclusive) || (!isStartMarker && isInclusive)) {
			while (node.getNextSibling() != null && node.getNodeType() != NodeType.FIELD_END)
				node = node.getNextSibling();

		}
	}

	// İşaretçilerden herhangi biri bir yorumun parçasıysa, yorumun kendisini dahil etmek için
	// imleci Yorum'a doğru ileri götürmeniz gerekir
	// CommentRangeEnd düğümünden sonra bulunan düğüm.
	if (node.getNodeType() == NodeType.COMMENT_RANGE_END) {
		while (node.getNextSibling() != null && node.getNodeType() != NodeType.COMMENT)
			node = node.getNextSibling();

	}

	// Klonlanmış düğümümüzde karşılık gelen düğümü dizine göre bulun ve döndürün.
	// Başlangıç ve bitiş düğümü aynıysa, bazı alt düğümler zaten
	// kaldırıldı. Çıkar
	// doğru dizini elde etmek için fark.
	int indexDiff = node.getParentNode().getChildNodes().getCount() - cloneNode.getChildNodes().getCount();

	// Alt düğüm sayısı aynı.
	if (indexDiff == 0)
		node = cloneNode.getChildNodes().get(node.getParentNode().indexOf(node));
	else
		node = cloneNode.getChildNodes().get(node.getParentNode().indexOf(node) - indexDiff);

	// İşaretçiye kadar olan/işaretleyiciden düğümleri kaldırın.
	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();
	}

	// İşlemden sonra bileşik düğüm boş olabilir. varsa dahil etmeyin
	// BT.
	if (!(isStartMarker && isEndMarker)) {
		if (cloneNode.hasChildNodes())
			nodes.add(cloneNode);
	}
}

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

	// Boş bir belge oluşturun.
	Document dstDoc = new Document();
	// İlk paragrafı boş belgeden çıkarın.
	dstDoc.getFirstSection().getBody().removeAllChildren();

	// Listedeki her düğümü yeni belgeye aktarın. orijinali sakla
	// düğümün biçimlendirilmesi.
	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);
	}

	// Oluşturulan belgeyi iade edin.
	return dstDoc;
}

Artık bu yöntemleri kullanmaya ve bir Word belgesinden metin çıkarmaya hazırız.

Java Bir Word DOC’daki Paragraflar Arasındaki Metni Çıkarın

Bir Word DOCX belgesinde iki paragraf arasındaki içeriğin nasıl çıkarılacağını görelim. Java’da bu işlemi gerçekleştirmek için gereken adımlar aşağıdadır.

  • İlk olarak, Document sınıfını kullanarak Word belgesini yükleyin.
  • Document.getFirstSection().getChild(NodeType.PARAGRAPH, int, bool) yöntemini kullanarak başlangıç ve bitiş paragraflarının referansını iki nesneye alın.
  • Düğümleri bir nesneye ayıklamak için extractContent(startPara, endPara, true) yöntemini çağırın.
  • Ayıklanan içerikten oluşan belge oluşturmak için createDocument(Document, extractedNodes) yardımcı yöntemini çağırın.
  • Son olarak, Document.save(String) yöntemini kullanarak döndürülen belgeyi kaydedin.

Aşağıdaki kod örneği, Java’da bir Word DOCX’te 7. ve 11. paragraflar arasındaki metnin nasıl ayıklanacağını gösterir.

// Belgeyi yükle
Document doc = new Document("TestFile.doc");

// Düğümleri toplayın. GetChild yöntemi, 0 tabanlı dizin kullanır
Paragraph startPara = (Paragraph) doc.getFirstSection().getChild(NodeType.PARAGRAPH, 6, true);
Paragraph endPara = (Paragraph) doc.getFirstSection().getChild(NodeType.PARAGRAPH, 10, true);
// Belgedeki bu düğümler arasındaki içeriği çıkarın. Bunları dahil et
// ekstraksiyonda belirteçler.
ArrayList extractedNodes = extractContent(startPara, endPara, true);

// İçeriği yeni bir ayrı belgeye yerleştirin ve diske kaydedin.
Document dstDoc = generateDocument(doc, extractedNodes);
dstDoc.save("output.doc");

Java DOC’tan Metin Çıkarma - Farklı Düğüm Türleri Arasında

Farklı düğüm türleri arasında da içerik çıkarabilirsiniz. Gösterim için, bir paragraf ve bir tablo arasındaki içeriği çıkaralım ve yeni bir Word belgesine kaydedelim. Aşağıdakiler, Java’daki bir Word belgesindeki farklı düğümler arasında metin ayıklama adımlarıdır.

  • Document sınıfını kullanarak Word belgesini yükleyin.
  • Document.getFirstSection().getChild(NodeType, int, bool) yöntemini kullanarak başlangıç ve bitiş düğümlerinin referansını iki nesneye alın.
  • Düğümleri bir nesneye ayıklamak için extractContent(startPara, endPara, true) yöntemini çağırın.
  • Ayıklanan içerikten oluşan belge oluşturmak için createDocument(Document, extractedNodes) yardımcı yöntemini çağırın.
  • Döndürülen belgeyi Document.save(String) yöntemini kullanarak kaydedin.

Aşağıdaki kod örneği, Java kullanılarak bir DOCX’te bir paragraf ile bir tablo arasındaki metnin nasıl ayıklanacağını gösterir.

// Belgeleri yükle
Document doc = new Document("TestFile.doc");

// Başlangıç paragrafının referansını al
Paragraph startPara = (Paragraph) doc.getLastSection().getChild(NodeType.PARAGRAPH, 2, true);
Table endTable = (Table) doc.getLastSection().getChild(NodeType.TABLE, 0, true);

// Belgedeki bu düğümler arasındaki içeriği çıkarın. Bu işaretleri ekstraksiyona dahil edin.
ArrayList extractedNodes = extractContent(startPara, endTable, true);

// İçeriği belgeye geri eklemeyi kolaylaştırmak için diziyi tersine çevirelim.
Collections.reverse(extractedNodes);

while (extractedNodes.size() > 0) {
    // Ters listeden son düğümü ekle
    endTable.getParentNode().insertAfter((Node) extractedNodes.get(0), endTable);
    // Eklemeden sonra bu düğümü listeden çıkarın.
    extractedNodes.remove(0);
}

// Oluşturulan belgeyi diske kaydedin.
doc.save("output.doc");

Java DOCX’ten Metin Çıkarıyor - Stillere Dayalı Paragraflar Arasında

Şimdi, stillere göre paragraflar arasında nasıl içerik çıkarılacağını kontrol edelim. Gösterim için, Word belgesindeki ilk “Başlık 1” ile ilk “Başlık 3” arasındaki içeriği çıkaracağız. Aşağıdaki adımlar, Java’da bunun nasıl başarılacağını göstermektedir.

  • İlk olarak, Document sınıfını kullanarak Word belgesini yükleyin.
  • Ardından, parametersByStyleName(Document, “Heading 1”) yardımcı yöntemini kullanarak paragrafları bir nesneye çıkarın.
  • ParagraflarByStyleName(Document, “Heading 3”) yardımcı yöntemini kullanarak paragrafları başka bir nesneye çıkarın.
  • extractContent(startPara, endPara, true) yöntemini çağırın ve her iki paragraf dizisindeki ilk öğeleri birinci ve ikinci parametreler olarak iletin.
  • Ayıklanan içerikten oluşan belge oluşturmak için createDocument(Document, extractedNodes) yardımcı yöntemini çağırın.
  • Son olarak, Document.save(String) yöntemini kullanarak döndürülen belgeyi kaydedin.

Aşağıdaki kod örneği, stilleri temel alan paragraflar arasında içeriğin nasıl ayıklanacağını gösterir.

// Belge yükle
Document doc = new Document(dataDir + "TestFile.doc");

// İlgili başlık stillerini kullanarak paragrafların bir listesini toplayın.
ArrayList parasStyleHeading1 = paragraphsByStyleName(doc, "Heading 1");
ArrayList parasStyleHeading3 = paragraphsByStyleName(doc, "Heading 3");

// Bu stillerle paragrafların ilk örneğini kullanın.
Node startPara1 = (Node) parasStyleHeading1.get(0);
Node endPara1 = (Node) parasStyleHeading3.get(0);

// Belgedeki bu düğümler arasındaki içeriği çıkarın. Bu işaretleri ekstraksiyona dahil etmeyin.
ArrayList extractedNodes = extractContent(startPara1, endPara1, false);

// İçeriği yeni bir ayrı belgeye yerleştirin ve diske kaydedin.
Document dstDoc = generateDocument(doc, extractedNodes);
dstDoc.save("output.doc");

Java Word Metin Çıkarıcı - Devamını Oku

Bu belgeleme makalesini kullanarak Word belgelerinden metin ayıklamanın diğer senaryolarını keşfedebilirsiniz.

DOC/DOCX’ten Metin Çıkarmak için Java API - Ücretsiz Lisans Alın

Aspose.Words for Java’yı değerlendirme sınırlamaları olmadan kullanmak için geçici lisans alabilirsiniz.

Çözüm

Bu makalede, Java’da MS Word DOC DOCX’ten nasıl metin çıkarılacağını öğrendiniz. Ayrıca, bir Word belgesindeki benzer veya farklı düğüm türleri arasında programlı olarak nasıl içerik çıkarılacağını gördünüz. Böylece, Java’da kendi MS Word metin çıkarıcınızı oluşturabilirsiniz. Ayrıca, belgeleri kullanarak Aspose.Words for Java’nın diğer özelliklerini keşfedebilirsiniz. Herhangi bir sorunuz olması durumunda forumumuz aracılığıyla bize bildirmekten çekinmeyin.

Ayrıca bakınız