package ted import ( "encoding/xml" "fmt" "strings" "tm/pkg/xmlparser" "tm/ted/eform/business_registration_information" "tm/ted/eform/contract" "tm/ted/eform/contract_award" "tm/ted/eform/prior_information" ) type ParserType string const ( ParserTypeContractNotice ParserType = "ContractNotice" ParserTypeContractAwardNotice ParserType = "ContractAwardNotice" ParserTypePriorInformationNotice ParserType = "PriorInformationNotice" ParserTypeBusinessRegistrationInformationNotice ParserType = "BusinessRegistrationInformationNotice" ) type TEDParser struct { ContractNotice xmlparser.Parser[contract.ContractNotice] ContractAwardNotice xmlparser.Parser[contract_award.ContractAwardNotice] PriorInformationNotice xmlparser.Parser[prior_information.PriorInformationNotice] BusinessRegistrationInformationNotice xmlparser.Parser[business_registration_information.BusinessRegistrationInformationNotice] } // NewTEDParser creates a new TED parser func NewTEDParser() *TEDParser { options := xmlparser.DefaultParserOptions() options.MaxSize = 50 * 1024 * 1024 // 50MB limit for TED XML files options.IgnoreUnknownElements = true // TED XML has many optional fields contractNoticeParser := xmlparser.NewParser[contract.ContractNotice](options) contractAwardNoticeParser := xmlparser.NewParser[contract_award.ContractAwardNotice](options) priorInformationNoticeParser := xmlparser.NewParser[prior_information.PriorInformationNotice](options) businessRegistrationInformationNoticeParser := xmlparser.NewParser[business_registration_information.BusinessRegistrationInformationNotice](options) return &TEDParser{ ContractNotice: contractNoticeParser, ContractAwardNotice: contractAwardNoticeParser, PriorInformationNotice: priorInformationNoticeParser, BusinessRegistrationInformationNotice: businessRegistrationInformationNoticeParser, } } // ParseAnyNotice parses XML content and detects the notice type automatically func (tp *TEDParser) Parse(content []byte) (interface{}, string, ParserType, error) { // First, detect the root element type rootElement, err := detectRootElement(content) if err != nil { return nil, "", ParserType(""), fmt.Errorf("failed to detect root element: %w", err) } // Parse based on the detected type switch ParserType(rootElement) { case ParserTypeContractNotice: notice, err := tp.ContractNotice.ParseBytes(content) return notice, notice.GetID(), ParserTypeContractNotice, err case ParserTypeContractAwardNotice: notice, err := tp.ContractAwardNotice.ParseBytes(content) return notice, notice.GetID(), ParserTypeContractAwardNotice, err case ParserTypePriorInformationNotice: notice, err := tp.PriorInformationNotice.ParseBytes(content) return notice, notice.GetID(), ParserTypePriorInformationNotice, err case ParserTypeBusinessRegistrationInformationNotice: notice, err := tp.BusinessRegistrationInformationNotice.ParseBytes(content) return notice, notice.GetID(), ParserTypeBusinessRegistrationInformationNotice, err default: return nil, "", ParserType(""), fmt.Errorf("unsupported notice type: %s", rootElement) } } // detectRootElement detects the root XML element name func detectRootElement(content []byte) (string, error) { decoder := xml.NewDecoder(strings.NewReader(string(content))) for { token, err := decoder.Token() if err != nil { return "", err } if startElement, ok := token.(xml.StartElement); ok { return startElement.Name.Local, nil } } }