You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Golang批量修改XML的lastModifiedBy字段:mxj解析丢字段的解决方法

Batch Update lastModifiedBy in XML Files Without Losing Fields

Got it, let's solve this problem of updating the lastModifiedBy field from Tom Hanks to Jerry Garcia across hundreds of XML files—without losing any fields in the process. Since converting XML to maps with mxj caused data loss, here are two reliable, targeted approaches that focus only on modifying that specific field:

Approach 1: Use xmlquery for Direct Node Manipulation

This library is perfect for querying and modifying XML nodes directly, which avoids the pitfalls of converting to maps and losing structure/namespaces.

  1. First, install the library:
go get github.com/antchfx/xmlquery
  1. Here's a complete batch processing example:
package main

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/antchfx/xmlquery"
)

func main() {
	// Replace with your target directory containing XML files
	targetDir := "./xml-files"

	err := filepath.Walk(targetDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && filepath.Ext(path) == ".xml" {
			fmt.Printf("Processing file: %s\n", path)
			if err := updateLastModifiedBy(path); err != nil {
				return fmt.Errorf("failed to process %s: %w", path, err)
			}
		}
		return nil
	})

	if err != nil {
		fmt.Printf("Batch processing failed: %v\n", err)
	}
}

func updateLastModifiedBy(filePath string) error {
	// Read the XML file
	f, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer f.Close()

	// Parse XML document
	doc, err := xmlquery.Parse(f)
	if err != nil {
		return err
	}

	// Query for the lastModifiedBy node (account for namespaces)
	// Adjust the XPath if your exact namespace/structure differs
	node := xmlquery.FindOne(doc, "//*[local-name()='lastModifiedBy']")
	if node != nil {
		// Update the node's text content
		node.InnerText = "Jerry Garcia"
	}

	// Write the modified XML back to the file
	outputFile, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer outputFile.Close()

	// Ensure proper XML declaration is preserved
	_, err = outputFile.WriteString(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` + "\n")
	if err != nil {
		return err
	}
	_, err = outputFile.WriteString(doc.OutputXML(true))
	return err
}

The XPath //*[local-name()='lastModifiedBy'] works even with namespaces (like your cp: prefix) by targeting the node's local name, so you don't have to worry about hardcoding namespace prefixes.

Approach 2: Use encoding/xml with Structs (Preserve All Fields)

If you prefer using Go's standard library, you can define a struct that matches the core properties section, while preserving other fields with the xml:",any" tag to avoid data loss.

package main

import (
	"encoding/xml"
	"fmt"
	"os"
	"path/filepath"
)

// Define struct to match the coreProperties element, preserving all other content
type CoreProperties struct {
	XMLName          xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/metadata/core-properties coreProperties"`
	LastModifiedBy   string   `xml:"lastModifiedBy"`
	// Catch-all for other elements/attributes to prevent loss
	OtherElements    []xml.Element `xml:",any"`
	OtherAttributes  []xml.Attr    `xml:",any"`
}

// Wrapper to hold the entire XML document
type XMLDocument struct {
	XMLDeclaration xml.ProcInst `xml:"xml,attr"`
	CoreProps      CoreProperties
	// Catch-all for other top-level elements
	OtherContent []xml.Element `xml:",any"`
}

func main() {
	targetDir := "./xml-files"

	err := filepath.Walk(targetDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && filepath.Ext(path) == ".xml" {
			fmt.Printf("Processing file: %s\n", path)
			if err := updateWithStdLib(path); err != nil {
				return fmt.Errorf("failed to process %s: %w", path, err)
			}
		}
		return nil
	})

	if err != nil {
		fmt.Printf("Batch processing failed: %v\n", err)
	}
}

func updateWithStdLib(filePath string) error {
	data, err := os.ReadFile(filePath)
	if err != nil {
		return err
	}

	var doc XMLDocument
	if err := xml.Unmarshal(data, &doc); err != nil {
		return err
	}

	// Update the field if it exists
	if doc.CoreProps.LastModifiedBy == "Tom Hanks" {
		doc.CoreProps.LastModifiedBy = "Jerry Garcia"
	}

	// Marshal back to XML, preserving formatting
	modifiedData, err := xml.MarshalIndent(doc, "", "  ")
	if err != nil {
		return err
	}

	// Prepend the XML declaration (MarshalIndent doesn't include it by default)
	finalData := append([]byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`+"\n"), modifiedData...)

	return os.WriteFile(filePath, finalData, 0644)
}

This approach uses the standard library and ensures no fields are lost by using the xml:",any" tag to capture any content not explicitly defined in the struct.

Both methods will safely update just the lastModifiedBy field while keeping all other XML content intact—perfect for your batch processing needs.

内容的提问来源于stack exchange,提问作者Gofurther

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:13:03