diff --git a/cdrc/xml.go b/cdrc/xml.go index b56002195..e60525c8b 100644 --- a/cdrc/xml.go +++ b/cdrc/xml.go @@ -26,7 +26,7 @@ import ( "strings" "time" - "github.com/beevik/etree" + "github.com/antchfx/xmlquery" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" @@ -34,17 +34,18 @@ import ( // getElementText will process the node to extract the elementName's text out of it (only first one found) // returns utils.ErrNotFound if the element is not found in the node -func elementText(xmlElement *etree.Element, elmntPath string) (string, error) { - elmnt := xmlElement.FindElement(elmntPath) +func elementText(xmlElement *xmlquery.Node, elmntPath string) (string, error) { + elmnt := xmlquery.FindOne(xmlElement, elmntPath) if elmnt == nil { return "", utils.ErrNotFound } - return elmnt.Text(), nil + return elmnt.InnerText(), nil + } // handlerUsageDiff will calculate the usage as difference between timeEnd and timeStart // Expects the 2 arguments in template separated by | -func handlerSubstractUsage(xmlElement *etree.Element, argsTpl config.RSRParsers, cdrPath utils.HierarchyPath, timezone string) (time.Duration, error) { +func handlerSubstractUsage(xmlElement *xmlquery.Node, argsTpl config.RSRParsers, cdrPath utils.HierarchyPath, timezone string) (time.Duration, error) { var argsStr string for _, rsrArg := range argsTpl { if rsrArg.Rules == utils.HandlerArgSep { @@ -79,21 +80,20 @@ func handlerSubstractUsage(xmlElement *etree.Element, argsTpl config.RSRParsers, func NewXMLRecordsProcessor(recordsReader io.Reader, cdrPath utils.HierarchyPath, timezone string, httpSkipTlsCheck bool, cdrcCfgs []*config.CdrcConfig, filterS *engine.FilterS) (*XMLRecordsProcessor, error) { - xmlDocument := etree.NewDocument() // create new document - xmlDocument.ReadSettings.CharsetReader = func(label string, input io.Reader) (io.Reader, error) { // fix for enconding != UTF-8 - return input, nil - } - if _, err := xmlDocument.ReadFrom(recordsReader); err != nil { // read file and build xml document + //create doc + doc, err := xmlquery.Parse(recordsReader) + if err != nil { return nil, err } xmlProc := &XMLRecordsProcessor{cdrPath: cdrPath, timezone: timezone, httpSkipTlsCheck: httpSkipTlsCheck, cdrcCfgs: cdrcCfgs, filterS: filterS} - xmlProc.cdrXmlElmts = xmlDocument.Root().FindElements(cdrPath.AsString("/", true)) + + xmlProc.cdrXmlElmts = xmlquery.Find(doc, cdrPath.AsString("/", true)) return xmlProc, nil } type XMLRecordsProcessor struct { - cdrXmlElmts []*etree.Element // result of splitting the XML doc into CDR elements + cdrXmlElmts []*xmlquery.Node // result of splitting the XML doc into CDR elements procItems int // current number of processed records from file cdrPath utils.HierarchyPath // path towards one CDR element timezone string @@ -137,7 +137,7 @@ func (xmlProc *XMLRecordsProcessor) ProcessNextRecord() (cdrs []*engine.CDR, err return cdrs, nil } -func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity *etree.Element, cdrcCfg *config.CdrcConfig, tenant string) (*engine.CDR, error) { +func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity *xmlquery.Node, cdrcCfg *config.CdrcConfig, tenant string) (*engine.CDR, error) { cdr := &engine.CDR{OriginHost: "0.0.0.0", Source: cdrcCfg.CdrSourceId, ExtraFields: make(map[string]string), Cost: -1} var lazyHttpFields []*config.FCTemplate var err error @@ -206,14 +206,14 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity *etree.Element, cdrcCf } // newXmlProvider constructs a DataProvider -func newXmlProvider(req *etree.Element, cdrPath utils.HierarchyPath) (dP config.DataProvider) { +func newXmlProvider(req *xmlquery.Node, cdrPath utils.HierarchyPath) (dP config.DataProvider) { dP = &xmlProvider{req: req, cdrPath: cdrPath, cache: config.NewNavigableMap(nil)} return } // xmlProvider implements engine.DataProvider so we can pass it to filters type xmlProvider struct { - req *etree.Element + req *xmlquery.Node cdrPath utils.HierarchyPath //used to compute relative path cache *config.NavigableMap } diff --git a/cdrc/xml_test.go b/cdrc/xml_test.go index 22f8a0348..aaac254d5 100644 --- a/cdrc/xml_test.go +++ b/cdrc/xml_test.go @@ -19,13 +19,13 @@ package cdrc import ( "bytes" - "io" "path" "reflect" + "strings" "testing" "time" - "github.com/beevik/etree" + "github.com/antchfx/xmlquery" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" @@ -167,15 +167,11 @@ var cdrXmlBroadsoft = ` ` func TestXMLElementText(t *testing.T) { - doc := etree.NewDocument() - doc.ReadSettings.CharsetReader = func(label string, input io.Reader) (io.Reader, error) { - return input, nil - } - if err := doc.ReadFromBytes([]byte(cdrXmlBroadsoft)); err != nil { + doc, err := xmlquery.Parse(strings.NewReader(cdrXmlBroadsoft)) + if err != nil { t.Error(err) } - - cdrs := doc.FindElements(path.Join("/broadWorksCDR/cdrData/")) + cdrs := xmlquery.Find(doc, path.Join("/broadWorksCDR/cdrData/")) cdrWithoutUserNr := cdrs[0] if _, err := elementText(cdrWithoutUserNr, "basicModule/userNumber"); err != utils.ErrNotFound { t.Error(err) @@ -194,15 +190,12 @@ func TestXMLElementText(t *testing.T) { } func TestXMLHandlerSubstractUsage(t *testing.T) { - doc := etree.NewDocument() - doc.ReadSettings.CharsetReader = func(label string, input io.Reader) (io.Reader, error) { - return input, nil - } - if err := doc.ReadFromBytes([]byte(cdrXmlBroadsoft)); err != nil { + doc, err := xmlquery.Parse(strings.NewReader(cdrXmlBroadsoft)) + if err != nil { t.Error(err) } - cdrs := doc.FindElements(path.Join("/broadWorksCDR/cdrData/")) + cdrs := xmlquery.Find(doc, path.Join("/broadWorksCDR/cdrData/")) cdrWithUsage := cdrs[1] if usage, err := handlerSubstractUsage(cdrWithUsage, config.NewRSRParsersMustCompile("~broadWorksCDR.cdrData.basicModule.releaseTime;|;~broadWorksCDR.cdrData.basicModule.answerTime", true), @@ -516,12 +509,12 @@ var xmlContent = ` ` func TestXMLElementText3(t *testing.T) { - doc := etree.NewDocument() - if err := doc.ReadFromString(xmlContent); err != nil { + doc, err := xmlquery.Parse(strings.NewReader(xmlContent)) + if err != nil { t.Error(err) } hPath2 := utils.ParseHierarchyPath("File.CDRs.Call", "") - cdrs := doc.Root().FindElements(hPath2.AsString("/", true)) + cdrs := xmlquery.Find(doc, hPath2.AsString("/", true)) if len(cdrs) != 3 { t.Errorf("Expecting: 3, received: %+v", len(cdrs)) } @@ -530,11 +523,7 @@ func TestXMLElementText3(t *testing.T) { t.Error(err) } - absolutePath := utils.ParseHierarchyPath("File.CDRs.Call.SignalingInfo.PChargingVector.icidvalue", "") - hPath := utils.ParseHierarchyPath(cdrs[1].GetPath(), "") - relPath := utils.HierarchyPath(absolutePath[len(hPath):]) // Need relative path to the xmlElmnt - - if val, err := elementText(cdrs[1], relPath.AsString("/", false)); err != nil { + if val, err := elementText(cdrs[1], "SignalingInfo/PChargingVector/icidvalue"); err != nil { t.Error(err) } else if val != "46d7974398c2671016afccc3f2c428c7" { t.Errorf("Expecting: 46d7974398c2671016afccc3f2c428c7, received: %s", val) diff --git a/glide.lock b/glide.lock index b544ec696..40bb67882 100644 --- a/glide.lock +++ b/glide.lock @@ -105,6 +105,8 @@ imports: - internal/scram - name: github.com/dlintw/goconf version: dcc070983490608a14480e3bf943bad464785df5 -- name: github.com/beevik/etree - version: 90dafc1e1f114dfb9576218bb43c03fb854d1b34 +- name: github.com/antchfx/xmlquery + version: 07935b1c0f2e6f0efa02c98cd70e223d70218955 +- name: github.com/antchfx/xpath + version: 3de91f3991a1af6e495d49c9218318b5544b20e3 testImports: [] diff --git a/glide.yaml b/glide.yaml index 413d35fca..e7931b824 100644 --- a/glide.yaml +++ b/glide.yaml @@ -41,4 +41,5 @@ import: - package: github.com/cgrates/radigo - package: github.com/cgrates/ltcache - package: github.com/dlintw/goconf -- package: github.com/beevik/etree \ No newline at end of file +- package: github.com/antchfx/xmlquery +- package: github.com/antchfx/xpath \ No newline at end of file