1
votes

Below is the XML snippet of an SSIS package; I'm trying to write an XPath query to find all "SELECT *" statements from the SSIS package.

I'm getting below error

ERROR: Caused by: com.sun.org.apache.xpath.internal.domapi.XPathStylesheetDOM3Exception: Prefix must resolve to a namespace: SQLTask

XML:

    <DTS:Executable
      DTS:refId="Package\TEST\TEST_COUNT"
      <DTS:ObjectData>
        <SQLTask:SqlTaskData
          SQLTask:Connection="{F7343EC3-A89E-4236-962C-FD2EB8B9491E}"
          SQLTask:SqlStatementSource="select * from dbo.TEST where colname1=? and colname2=?"
          SQLTask:ResultType="ResultSetType_SingleRow" xmlns:SQLTask="www.microsoft.com/sqlserver/dts/tasks/sqltask">
        </SQLTask:SqlTaskData>
      </DTS:ObjectData>
    </DTS:Executable>

Xpath query:

//SQLTask:SqlTaskData[contains(translate(@SQLTask:SqlStatementSource,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') ,"select *")]/../../@DTS:refId

I was able to evaluate the xpath expression successfully from https://www.freeformatter.com/xpath-tester.html. However the actual packages are validated through XPath rules defined in SonarQube from where I'm getting this error.

1
You are using the SQLTask: prefix without declaring it. In other words, the error message means that SonarQube has no idea which namespace this prefix refers to. Search how to declare XML namespaces in SonarQube. - Tomalak
@Tomalak but the same expression worked when I uploaded the xml file in freeformatter.com/xpath-tester.html - Leo
This might be, but freeformatter and SonarQube are not the same thing. - Tomalak
There's no mention of XML namespace support in SonarQube's documentation, so if you cannot fix your XML to make it namespace-well-formed, you may have to use local-name() to defeat namespaces in XPath as described in this answer. - kjhughes
Could you figure it out or do you still need an answer? - wp78de

1 Answers

1
votes

Here is your XPath query with skirted namespaces as pointed out in comments:

//*:SqlTaskData[contains(translate(@*:SqlStatementSource,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') ,"select *")]/../../@*:refId

For an explanation, read kjhughes excellent answer here.

Now, getting all SqlStatementSource that contain "select *" works the same way:

//*:SqlTaskData[contains(translate(@*:SqlStatementSource,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') ,"select *")]/@*:SqlStatementSource

Online Demo

or use the local-name() function as you already found out:

 //*[local-name()='SqlTaskData'][contains(translate(@*[local-name()='SqlStatementSource'],'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') ,"select count(*)")]/@*[local-name()='SqlStatementSource']