package ted import ( "encoding/xml" "fmt" "strings" "tm/pkg/xmlparser" ) type TEDParser struct { ContractNotice xmlparser.Parser[ContractNotice] ContractAwardNotice xmlparser.Parser[ContractAwardNotice] PriorInformationNotice xmlparser.Parser[PriorInformationNotice] // BusinessRegistrationInformationNotice xmlparser.Parser[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[ContractNotice](options) contractAwardNoticeParser := xmlparser.NewParser[ContractAwardNotice](options) priorInformationNoticeParser := xmlparser.NewParser[PriorInformationNotice](options) // businessRegistrationInformationNoticeParser := xmlparser.NewParser[BusinessRegistrationInformationNotice](options) return &TEDParser{ ContractNotice: contractNoticeParser, ContractAwardNotice: contractAwardNoticeParser, PriorInformationNotice: priorInformationNoticeParser, // BusinessRegistrationInformationNotice: businessRegistrationInformationNoticeParser, } } // ParseXML automatically detects and parses any supported TED XML document type func (p *TEDParser) ParseXML(content []byte) (*ParsedDocument, string, DocumentType, error) { // First, detect the root element type rootElement, err := detectRootElement(content) if err != nil { return nil, "", DocumentType(""), fmt.Errorf("failed to detect root element: %w", err) } parsedDoc := &ParsedDocument{Type: DocumentType(rootElement)} switch parsedDoc.Type { case DocumentTypeContractNotice: notice, err := p.ContractNotice.ParseBytes(content) if err != nil { return nil, "", DocumentType(""), fmt.Errorf("failed to parse contract notice: %w", err) } parsedDoc.ContractNotice = notice return parsedDoc, notice.GetID(), parsedDoc.Type, nil case DocumentTypeContractAwardNotice: notice, err := p.ContractAwardNotice.ParseBytes(content) if err != nil { return nil, "", DocumentType(""), fmt.Errorf("failed to parse contract award notice: %w", err) } parsedDoc.ContractAwardNotice = notice return parsedDoc, notice.GetID(), parsedDoc.Type, nil case DocumentTypePriorInformationNotice: notice, err := p.PriorInformationNotice.ParseBytes(content) if err != nil { return nil, "", DocumentType(""), fmt.Errorf("failed to parse prior information notice: %w", err) } parsedDoc.PriorInformationNotice = notice return parsedDoc, notice.GetID(), parsedDoc.Type, nil default: return nil, "", DocumentType(""), fmt.Errorf("unsupported document type: %s", parsedDoc.Type) } } // 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 } } }