You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: junit_report.go
    path of file: ./repos/podman/vendor/github.com/onsi/ginkgo/v2/reporters
    
    the code of the file until where you have to start completion: /*

JUnit XML Reporter for Ginkgo

For usage instructions: http://onsi.github.io/ginkgo/#generating_junit_xml_output

The schema used for the generated JUnit xml file was adapted from https://llg.cubic.org/docs/junit/

*/

package reporters

import (
	"encoding/xml"
	"fmt"
	"os"
	"path"
	"regexp"
	"strings"

	"github.com/onsi/ginkgo/v2/config"
	"github.com/onsi/ginkgo/v2/types"
)

type JunitReportConfig struct {
	// Spec States for which no timeline should be emitted for system-err
	// set this to types.SpecStatePassed|types.SpecStateSkipped|types.SpecStatePending to only match failing specs
	OmitTimelinesForSpecState types.SpecState

	// Enable OmitFailureMessageAttr to prevent failure messages appearing in the "message" attribute of the Failure and Error tags
	OmitFailureMessageAttr bool

	//Enable OmitCapturedStdOutErr to prevent captured stdout/stderr appearing in system-out
	OmitCapturedStdOutErr bool

	// Enable OmitSpecLabels to prevent labels from appearing in the spec name
	OmitSpecLabels bool

	// Enable OmitLeafNodeType to prevent the spec leaf node type from appearing in the spec name
	OmitLeafNodeType bool

	// Enable OmitSuiteSetupNodes to prevent the creation of testcase entries for setup nodes
	OmitSuiteSetupNodes bool
}

type JUnitTestSuites struct {
	XMLName xml.Name `xml:"testsuites"`
	// Tests maps onto the total number of specs in all test suites (this includes any suite nodes such as BeforeSuite)
	Tests int `xml:"tests,attr"`
	// Disabled maps onto specs that are pending and/or skipped
	Disabled int `xml:"disabled,attr"`
	// Errors maps onto specs that panicked or were interrupted
	Errors int `xml:"errors,attr"`
	// Failures maps onto specs that failed
	Failures int `xml:"failures,attr"`
	// Time is the time in seconds to execute all test suites
	Time float64 `xml:"time,attr"`

	//The set of all test suites
	TestSuites []JUnitTestSuite `xml:"testsuite"`
}

type JUnitTestSuite struct {
	// Name maps onto the description of the test suite - maps onto Report.SuiteDescription
	Name string `xml:"name,attr"`
	// Package maps onto the absolute path to the test suite - maps onto Report.SuitePath
	Package string `xml:"package,attr"`
	// Tests maps onto the total number of specs in the test suite (this includes any suite nodes such as BeforeSuite)
	Tests int `xml:"tests,attr"`
	// Disabled maps onto specs that are pending
	Disabled int `xml:"disabled,attr"`
	// Skiped maps onto specs that are skipped
	Skipped int `xml:"skipped,attr"`
	// Errors maps onto specs that panicked or were interrupted
	Errors int `xml:"errors,attr"`
	// Failures maps onto specs that failed
	Failures int `xml:"failures,attr"`
	// Time is the time in seconds to execute all the test suite - maps onto Report.RunTime
	Time float64 `xml:"time,attr"`
	// Timestamp is the ISO 8601 formatted start-time of the suite - maps onto Report.StartTime
	Timestamp string `xml:"timestamp,attr"`

	//Properties captures the information stored in the rest of the Report type (including SuiteConfig) as key-value pairs
	Properties JUnitProperties `xml:"properties"`

	//TestCases capture the individual specs
	TestCases []JUnitTestCase `xml:"testcase"`
}

type JUnitProperties struct {
	Properties []JUnitProperty `xml:"property"`
}

func (jup JUnitProperties) WithName(name string) string {
	for _, property := range jup.Properties {
		if property.Name == name {
			return property.Value
		}
	}
	return ""
}

type JUnitProperty struct {
	Name  string `xml:"name,attr"`
	Value string `xml:
    
func GenerateJUnitReportWithConfig(report types.Report, dst string, config JunitReportConfig) error {
	suite := JUnitTestSuite{
		Name:      report.SuiteDescription,
		Package:   report.SuitePath,
		Time:      report.RunTime.Seconds(),
		Timestamp: report.StartTime.Format("2006-01-02T15:04:05"),
		Properties: JUnitProperties{
			Properties: []JUnitProperty{
				{"SuiteSucceeded", fmt.Sprintf("%t", report.SuiteSucceeded)},
				{"SuiteHasProgrammaticFocus", fmt.Sprintf("%t", report.SuiteHasProgrammaticFocus)},
				{"SpecialSuiteFailureReason", strings.Join(report.SpecialSuiteFailureReasons, ",")},
				{"SuiteLabels", fmt.Sprintf("[%s]", strings.Join(report.SuiteLabels, ","))},
				{"RandomSeed", fmt.Sprintf("%d", report.SuiteConfig.RandomSeed)},
				{"RandomizeAllSpecs", fmt.Sprintf("%t", report.SuiteConfig.RandomizeAllSpecs)},
				{"LabelFilter", report.SuiteConfig.LabelFilter},
				{"FocusStrings", strings.Join(report.SuiteConfig.FocusStrings, ",")},
				{"SkipStrings", strings.Join(report.SuiteConfig.SkipStrings, ",")},
				{"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")},
				{"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")},
				{"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)},
				{"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)},
				{"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)},
				{"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)},
				{"ParallelTotal", fmt.Sprintf("%d", report.SuiteConfig.ParallelTotal)},
				{"OutputInterceptorMode", report.SuiteConfig.OutputInterceptorMode},
			},
		},
	}
	for _, spec := range report.SpecReports {
		if config.OmitSuiteSetupNodes && spec.LeafNodeType != types.NodeTypeIt {
			continue
		}
		name := fmt.Sprintf("[%s]", spec.LeafNodeType)
		if config.OmitLeafNodeType {
			name = ""
		}
		if spec.FullText() != "" {
			name = name + " " + spec.FullText()
		}
		labels := spec.Labels()
		if len(labels) > 0 && !config.OmitSpecLabels {
			name = name + " [" + strings.Join(labels, ", ") + "]"
		}
		owner := ""
		for _, label := range labels {
			if matches := ownerRE.FindStringSubmatch(label); len(matches) == 2 {
				owner = matches[1]
			}
		}
		name = strings.TrimSpace(name)

		test := JUnitTestCase{
			Name:      name,
			Classname: report.SuiteDescription,
			Status:    spec.State.String(),
			Time:      spec.RunTime.Seconds(),
			Owner:     owner,
		}
		if !spec.State.Is(config.OmitTimelinesForSpecState) {
			test.SystemErr = systemErrForUnstructuredReporters(spec)
		}
		if !config.OmitCapturedStdOutErr {
			test.SystemOut = systemOutForUnstructuredReporters(spec)
		}
		suite.Tests += 1

		switch spec.State {
		case types.SpecStateSkipped:
			message := "skipped"
			if spec.Failure.Message != "" {
				message += " - " + spec.Failure.Message
			}
			test.Skipped = &JUnitSkipped{Message: message}
			suite.Skipped += 1
		case types.SpecStatePending:
			test.Skipped = &JUnitSkipped{Message: "pending"}
			suite.Disabled += 1
		case types.SpecStateFailed:
			test.Failure = &JUnitFailure{
				Message:     spec.Failure.Message,
				Type:        "failed",
				Description: failureDescriptionForUnstructuredReporters(spec),
			}
			if config.OmitFailureMessageAttr {
				test.Failure.Message = ""
			}
			suite.Failures += 1
		case types.SpecStateTimedout:
			test.Failure = &JUnitFailure{
				Message:     spec.Failure.Message,
				Type:        "timedout",
				Description: failureDescriptionForUnstructuredReporters(spec),
			}
			if config.OmitFailureMessageAttr {
				test.Failure.Message = ""
			}
			suite.Failures += 1
		case types.SpecStateInterrupted:
			test.Error = &JUnitError{
				Message:     spec.Failure.Message,
				Type:        "interrupted",
				Description: failureDescriptionForUnstructuredReporters(spec),
			}
			if config.OmitFailureMessageAttr {
				test.Error.Message = ""
			}
			suite.Errors += 1
		case types.SpecStateAborted:
			test.Failure = &JUnitFailure{
				Message:     spec.Failure.Message,
				Type:        "aborted",
				Description: failureDescriptionForUnstructuredReporters(spec),
			}
			if config.OmitFailureMessageAttr {
				test.Failure.Message = ""
			}
			suite.Errors += 1
		case types.SpecStatePanicked:
			test.Error = &JUnitError{
				Message:     spec.Failure.ForwardedPanic,
				Type:        "panicked",
				Description: failureDescriptionForUnstructuredReporters(spec),
			}
			if config.OmitFailureMessageAttr {
				test.Error.Message = ""
			}
			suite.Errors += 1
		}

		suite.TestCases = append(suite.TestCases, test)
	}

	junitReport := JUnitTestSuites{
		Tests:      suite.Tests,
		Disabled:   suite.Disabled + suite.Skipped,
		Errors:     suite.Errors,
		Failures:   suite.Failures,
		Time:       suite.Time,
		TestSuites: []JUnitTestSuite{suite},
	}

	if err := os.MkdirAll(path.Dir(dst), 0770); err != nil {
		return err
	}
	f, err := os.Create(dst)
	if err != nil {
		return err
	}
	f.WriteString(xml.Header)
	encoder := xml.NewEncoder(f)
	encoder.Indent("  ", "    ")
	encoder.Encode(junitReport)

	return f.Close()
}