0
votes

I tried to convert XML file into HTML using XSLT format but i got an error

RROR:  'Namespace prefix 'vuln' is undeclared.'
FATAL ERROR:  'Could not compile stylesheet' 

The XML file started with

<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet type="text/xsl" version ="2.0" href="nvdXSLT.xsl"?>
<nvd xmlns:cpe-lang="http://cpe.mitre.org/language/2.0" 
 xmlns:scapcore="http://scap.nist.gov/schema/scap-core/0.1" 
 xmlns:vuln="http://scap.nist.gov/schema/vulnerability/0.4" 
 xmlns:cvss="http://scap.nist.gov/schema/cvss-v2/0.2" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:patch="http://scap.nist.gov/schema/patch/0.1" 
 xmlns="http://scap.nist.gov/schema/feed/vulnerability/2.0" >
   <entry id="CVE-2007-5333">
   <vuln:vulnerable-software-list>
     <vuln:product>cpe:/a:apache_software_foundation:tomcat:4.1.34</vuln:product>
     <vuln:product>cpe:/a:apache_software_foundation:tomcat:4.1.37</vuln:product>
     <vuln:product>cpe:/a:apache:tomcat:4.1.24</vuln:product>
     <vuln:product>cpe:/a:apache:tomcat:5.5.5</vuln:product>
     <vuln:product>cpe:/a:apache:tomcat:5.5.2</vuln:product>
   </vuln:vulnerable-software-list>
   <vuln:cve-id>CVE-2007-5333</vuln:cve-id>
   <vuln:published-datetime>2008-02-11T20:00:00.000-05:00</vuln:published-datetime>
   <vuln:last-modified-datetime>2014-03-15T23:16:41.310-04:00</vuln:last-modified-datetime>
  </entry>
 </nvd>

And i created XSL transformer to transform the xml content into organized format and display the output on html format javax.xml.transform API. The XSL file as follow:

 <?xml version="1.0" encoding="UTF-8"?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"           
   xmlns:vuln="http://scap.nist.gov/schema/vulnerability/0.4" 
   xmlns:cvss="http://scap.nist.gov/schema/cvss-v2/0.2"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:patch="http://scap.nist.gov/schema/patch/0.1"
   xmlns="http://scap.nist.gov/schema/feed/vulnerability/2.0">
   <xsl:output method="html" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
    <!-- TODO: Auto-generated template -->
    <html>
    <body>
    <h1>Parsing NVD XML file</h1>
    <table border="1">
              <tr>
                 <th>hasAffectedProducts</th>       
              </tr>
    <xsl:for-each select="nvd/entry">
        <tr>
          <td><xsl:for-each select="/vuln:vulnerable-software-list"><xsl:value-of select="vuln:product" /></xsl:for-each></td>
                 </tr>
            <td><xsl:value-of select="vuln:cve-id" /></td>
            <td><xsl:value-of select="vuln:published-datetime" /></td>
            <td><xsl:value-of select="vuln:last-modified-datetime"/></td>
         .....

The JAVA API that I used to do transformation

  public void transform(String dataXML, String inputXSL, String outputHTML)
        throws TransformerConfigurationException, TransformerException {

    TransformerFactory factory = TransformerFactory.newInstance();
    StreamSource xslStream = new StreamSource(inputXSL);
    Transformer transformer = factory.newTransformer(xslStream);
    StreamSource in = new StreamSource(dataXML);
    StreamResult out = new StreamResult(outputHTML);
    transformer.transform(in, out);
    System.out.println("The generated HTML file is:" + outputHTML);

}

Simply, received XML file and XSL file and create output file int HTML format.

2
Your input XML is not namespace-well-formed as it uses the vuln prefix without declaring it. XSLT can only operate on namespace-well-formed XML so you need to get the XML fixed at source to declare its namespaces properly. - Ian Roberts
It fixed, but i got empty table, it seems XSL transformer doesn't work properly, any help please ?! - Tech
The transformer is working correctly, it's the stylesheet that is wrong ;-) - Ian Roberts
For future questions, please try to include examples that are truly representative of your real problem. If you're not sure whether or not a particular feature might be significant then it's better to include it anyway - it's much easier for us to filter out noise than to guess what might have been left out. - Ian Roberts
I totally agree BUT the current problem "empty output" comes out after solving the first one "namespace error". So, based on that i come up with updates on my original post to be adjusted with questions that i have been asked. Thanks - Tech

2 Answers

0
votes

Your error is very clear as to why it can't compile the stylesheet:

ERROR:  'Namespace prefix 'vuln' is undeclared.'
FATAL ERROR:  'Could not compile stylesheet' 

vuln is a namespace you need to be declared in the root of the xslt:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:vuln="http://www.someurl.com/vuln">

I think you want something like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:vuln="http://scap.nist.gov/schema/vulnerability/0.4" xmlns:cvss="http://scap.nist.gov/schema/cvss-v2/0.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:patch="http://scap.nist.gov/schema/patch/0.1" xmlns="http://scap.nist.gov/schema/feed/vulnerability/2.0">
    <xsl:output method="html" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <!-- TODO: Auto-generated template -->
        <html>
            <body>
                <h1>Parsing NVD XML file</h1>
                <table border="1">
                    <tr>
                        <th>hasAffectedProducts</th>
                    </tr>
                    <xsl:for-each select="/nvd/entry">
                        <xsl:for-each select="vuln:vulnerable-software-list">
                            <tr>
                                <td>
                                    <xsl:value-of select="vuln:product"/>
                                </td>
                            </tr>
                        </xsl:for-each>
                        <tr>
                            <td>
                                <xsl:value-of select="vuln:cve-id"/>
                            </td>
                            <td>
                                <xsl:value-of select="vuln:published-datetime"/>
                            </td>
                            <td>
                                <xsl:value-of select="vuln:last-modified-datetime"/>
                            </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>
0
votes

You have two issues with your stylesheet.

The first issue involves the namespaces. You need to bind the vuln prefix to the same namespace URI in the stylesheet as it is in the document, and you also need to bind a prefix to the http://scap.nist.gov/schema/feed/vulnerability/2.0 URI which is the default namespace of your document. Unprefixed names in XPath expressions refer to elements that are not in a namespace, so to match elements in a document with a default xmlns you must use a prefix in the XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:vuln="http://scap.nist.gov/schema/vulnerability/0.4"
     xmlns:feed="http://scap.nist.gov/schema/feed/vulnerability/2.0">

You should also remove the default namespace declaration xmlns="http://scap.nist.gov/schema/feed/vulnerability/2.0" from the stylesheet as this will put the output elements in this namespace rather than treating them as HTML.

With these namespace bindings in place you can correct the outer for-each to look for elements in the right namespace

<xsl:for-each select="feed:nvd/feed:entry">

The second problem is in the inner for-each

 <xsl:for-each select="feed:nvd/feed:entry">
    <tr>
      <td><xsl:for-each select="/vuln:vulnerable-software-list">

where you're using an absolute path where you should be using a relative one - you're trying to for-each over all the vulnerable-software-list elements at the root level of your document and print their respective first product child. The transformer is correctly giving you an empty node set as the root element is actually called nvd and is in a different namespace.

If instead you want to for-each over all the product elements in the current entry then change it to

<xsl:for-each select="vuln:vulnerable-software-list/vuln:product">
  <xsl:value-of select="." />
</xsl:for-each>