Best xml questions in March 2012

How can I get array of elements, including missing elements, using XPath in XSLT?

10 votes

Given the following XML-compliant HTML:

<div>
 <a>a1</a>
 <b>b1</b>
</div>

<div>
 <b>b2</b>
</div>

<div>
 <a>a3</a>
 <b>b3</b>
 <c>c3</c>
</div>

doing //a will return:

[a1,a3]

The problem with above is that the third column data is now in second place, when A is not found it is completely skipped.

how can you express an xpath to get all A elements which will return:

[a1, null, a3]

same case for //c, I wonder if it's possible to get

[null, null, c3]

UPDATE: consider another scenario where are no common parents <div>.

<h1>heading1</h1>
 <a>a1</a>
 <b>b1</b>


<h1>heading2</h1>
 <b>b2</b>


<h1>heading3</h1>
 <a>a3</a>
 <b>b3</b>
 <c>c3</c>

UPDATE: I am now able to use XSLT as well.

There is no null value in XPath. There's a semi-related question here which also explains this: http://www.velocityreviews.com/forums/t686805-xpath-query-to-return-null-values.html

Realistically, you've got three options:

  1. Don't use XPath at all.
  2. Use this: //a | //div[not(a)], which would return the div element if there was no a within it, and have your Java code handle any div's returned as 'no a element present'. Depending on the context, this may even allow you to output something more useful if required, as you'll have access to the entire contents of the div, for example an error 'no a element found in div (some identifier)'.
  3. Preprocess your XML with an XSLT that inserts a elements in any div element that does not already have one with a suitable default.

Your second case is a little tricky, and to be honest, I'd actually recommend not using XPath for it at all, but it can be done:

//a | //h1[not(following-sibling::a) or generate-id(.) != generate-id(following-sibling::a[1]/preceding-sibling::h1[1])]

This will match any a elements, or any h1 elements where no following a element exists before the next h1 element, or the end of the document. As Dimitre pointed out though, this only works if you're using it from within XSLT, as generate-id is an XSLT function.

If you're not using it from within XLST, you can use this rather contrived formula:

//a | //h1[not(following-sibling::a) or count(. | preceding-sibling::h1) != count(following-sibling::a[1]/preceding-sibling::h1)]

It works by matching h1 elements where the count of itself and all preceding h1 elements is not the same as the count of all h1 elements preceding the next a. There may be a more efficient way of doing it in XPath, but if it's going to get any more contrived than that, I'd definitely recommend not using XPath at all.

reverse-lookup Digital Object Identifier given table of citations?

6 votes

I have a table of citations that includes the last name of the first author, the title, journal, year, and page numbers for each citation.

I have posted the first few lines of the table on google docs, or the csv version (not all records have a doi)

I would like to be able to query the digital object identifier for each of these citations. For the titles, it would be best if the query could handle "fuzzy matching".

How can I do this?

The table is currently in MySQL, but it would be sufficient to start and end with a .csv file (I would appreciate an answer that goes from start to finish) (or, since I mostly use R, an R data frame).

Here are two options

CSV upload

I have found another promising solution that does not work as well in practice as in

CrossRef allows you to upload the linked csv directly, and then performs a text query here: http://www.crossref.org/stqUpload/

However, only 18 of the 250 queries (~7%) returned a doi.

XML Query

Based on the answer by Brian Diggs, here an attempt that does 95% of the work - toward writing the xml-based query, it still has a few bugs that require some deletion using sed. But the biggest problem that my "session timed out" when the query was submitted.

the xml syntax includes an option to use fuzzy matching.

the doiquery.xml contains the template text in @Brians answer; the citations.csv is linked above.

library(XML)
doiquery.xml <- xmlTreeParse('doiquery.xml')

query <- doiquery.xml$doc$children$query_batch[["body"]]

citations <- read.csv("citations.csv")

new.query <- function(citation, query = query){
  xmlValue(query[["author"]]) <- as.character(citation$author)
  xmlValue(query[["year"]]) <- as.character(citation$year)
  xmlValue(query[["article_title"]][["text"]]) <- citation$title
  xmlValue(query[["journal_title"]]) <- citation$journal
  return(query)
}


for (i in 1:nrow(citations)){
  q <- addChildren(q, add.query(citations[i,]))
}
axml <- addChildren(doiquery.xml$doc$children$query_batch, q )

saveXML(axml, file = 'foo.xml')

CSV to XML Converter

Creativyst software provides a web based CSV to XML converter.

Steps:

  1. Enter columnames in ElementID's field,
  2. "document" in DocID field
  3. "query" in RowID field
  4. Copy / paste csv in "Input CSV file".
  5. Click Convert

Also, see this related question: Shell script to parse CSV to an XML query?

String replace in substring

6 votes

I want to write a method for a Java class. The method accepts as input a string of XML data as given below.

<?xml version="1.0" encoding="UTF-8"?>
<library>

    <book>
        <name> <> Programming in ANSI C <> </name>
        <author> <>  Balaguruswamy <> </author>
        <comment> <> This comment may contain xml entities such as &, < and >. <> </comment>
    </book>

    <book>
        <name> <> A Mathematical Theory of Communication <> </name>
        <author> <> Claude E. Shannon <> </author>
        <comment> <> This comment also may contain xml entities. <> </comment>
    </book>

    <!-- This library contains more than ten thousand books. -->
</library>

The XML string contains a lot of substring starting and ending with <>. The substring may contain XML entities such as >, <, &, ' and ". The method need to replace them with &gt;, &lt;, &amp;. &apos; and &quot; respectively.

Is there any regular-expression method in Java to accomplish this task?

Is this data being passed to you, or can you control it? If so, then I would suggest using a CDATA block. If you are really unsure about the data being entered into the xml blocks, then just wrap everything in a CDATA before it is saved to the DB

If you do not have control over this, then as far as I know, this will take a fair amount of coding due to the number of edge cases you possibly will have to deal with. Not something that a simple regex will be able to deal with (if a valid block is starting, if one is ending, if one has already ended, etc)

Here is a very basic regex for the <> case, but the rest I really believe just get extremely complicated

\<\>* //For <> changes

XSLT to transform to HTML and format the HTML based on data in XML

6 votes

i am pretty new to XSLT / XML and HTML. I have a XML file that I currently convert to HTML in c# using an XSLT. The XML file represents nothing but data extracted from a table in a database. I can currently convert the XML file to HTML using XSLT fairly easily without much formating. the HTML when opened looks pretty ordinary. What i intend to is format the HTML i.e change the font, background color, font color etc based on certain key values in the XML document.

The XML is generated on a daily basis using C# code . the content of the XML file totally depends on the contents of the table in the database at that point in the day when the C# code is executed..

the XML looks something like this

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <defects>
    <Defectid>56</Defectid>
    <testid>111</testid>
    <summary>Release of DIT </summary>
    <DetectedDate>2011-09-21 </DetectedDate>
    <priority>2-Give High Attention</priority>
    <status>Ready to Test</status>
    <project>Business Intelligence</project>
    <assignedTo>peter</assignedTo>
    <detectedBy>john</detectedBy>
    <severity>3-Average</severity>
  </defects>
  <defects>
    <Defectid>829</Defectid>
    <testid>111</testid>
    <summary> Data request</summary>
    <DetectedDate>2012-01-12 </DetectedDate>
    <priority>3-Normal Queue</priority>
    <status>Open</status>
    <project>web</project>
    <assignedTo>tcm</assignedTo>
    <detectedBy>john</detectedBy>
    <severity>3-Average</severity>
  </defects>
  <defects>
    <Defectid>728</Defectid>
    <testid>999</testid>
    <summary>Data request</summary>
    <DetectedDate>2012-01-11</DetectedDate>
    <priority>3-Normal Queue</priority>
    <status>Fixed</status>
    <project>Business Intelligence</project>
    <assignedTo>chris</assignedTo>
    <detectedBy>peter</detectedBy>
    <severity>3-Average</severity>
  </defects>
</NewDataSet>

what i intend to do is generate and HTML table from this XML which would be in tabular format but the font color of the rows in the HTML table should be set based on "testid" attribute . i.e. for font color on the HTML should be unique per "testid" attribute. Since the rows per testid would change daily based on the data in the table in the database, I am not sure how this can be accomplished using XSLT.

the current XSLT looks something like this.. as you can see , I have hardcoded the font colors.

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html"/>
  <xsl:template match="/">
    <table  BORDER="1" CELLPADDING="3" CELLSPACING="2" WIDTH="100">
      <tr>
        <td nowrap="nowrap" width = "70">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Defect ID</b>
          </h1>
        </td>
        <td nowrap="nowrap" width = "70">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Test ID</b>
          </h1>
        </td>
        <td nowrap="nowrap" width = "400">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Summary</b>
          </h1>
        </td>
        <td nowrap="nowrap" width = "150">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Detected Date</b>
          </h1>
        </td>
        <td width = "200">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Priority</b>
          </h1>
        </td>
        <td width = "200">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Status</b>
          </h1>
        </td>
        <td width = "200">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Project</b>
          </h1>
        </td>
        <td nowrap="nowrap" width = "100">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Assigned To</b>
          </h1>
        </td>
        <td nowrap="nowrap" width = "100">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Detected By</b>
          </h1>
        </td>
        <td nowrap="nowrap" width = "80">
          <h1 style="font-family:verdana ;font-size:60%;color:green">
            <b>Severity</b>
          </h1>
        </td>
      </tr>
      <xsl:for-each select="//defects">

        <tr>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="Defectid"></xsl:value-of>
            </h1>
          </td>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="testid"/>
            </h1>
          </td>
          <td width = "400">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="summary"/>
            </h1>
          </td>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="DetectedDate"/>
            </h1>
          </td>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="priority"/>
            </h1>
          </td>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="status"/>
            </h1>
          </td>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="project"/>
            </h1>
          </td>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="assignedTo"/>
            </h1>
          </td>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="detectedBy"/>
            </h1>
          </td>
          <td width = "100">
            <h1 style="font-family:verdana ;font-size:60%;color:blue">
              <xsl:value-of select="severity"/>
            </h1>
          </td>

        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>

</xsl:stylesheet>

Does anybody know or could anybody guide me?

Below is a solution that applies up to 20 different colors - applying one particular color for each row with a specific testid.
Note that it is not important how many distinct testid's occur. Also note that color coding says nothing about the testid itself - but that's exactly the way you wanted it :-).

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
    version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:std="http://www.standardColors.com">

    <xsl:output method="html"/>

    <xsl:variable name="colors">
        <color>#0000FF</color>
        <color>#FF0000</color>
        <color>#00FFFF</color>
        <color>#FFFF00</color>
        <color>#347C2C</color>
        <color>#800080</color>
        <color>#3B9C9C</color>
        <color>#A52A2A</color>
        <color>#3BB9FF</color>
        <color>#FF00FF</color>
        <color>#6698FF</color>
        <color>#808000</color>
        <color>#8D38C9</color>
        <color>#ADD8E6</color>
        <color>#F660AB</color>
        <color>#F87217</color>
        <color>#F9B7FF</color>
        <color>#FFA500</color>
        <color>#FFE87C</color>
        <color>#8E35EF</color>
    </xsl:variable>

    <xsl:variable name="testIDs" select="distinct-values(//testid)"/>

    <xsl:variable name="colorList">
        <xsl:for-each select="$testIDs">
            <xsl:variable name="pos" select="position() mod 20"/>
            <xsl:copy-of select="$colors/color[$pos]"/>
        </xsl:for-each>
    </xsl:variable>

    <xsl:template match="/">
        <html>
            <head>
                <style>
                    th, td {
                        border: solid black 1px ;
                        padding: 3px;                       
                        border-spacing:2px;
                        border-collapse: collapse;
                        width: 100px;
                    }
                    th {
                        font-family:verdana;
                        font-size:60%;
                        color:green;
                        align:center;
                        white-space: nowrap;
                    }
                    <xsl:for-each select="$testIDs">
                    <xsl:variable name="pos" select="position()"/>
                     tr.testid<xsl:value-of select="."/> {
                        font-family:verdana;
                        font-size:60%;
                        font-weight:bold;
                        color:<xsl:value-of select="$colorList/color[$pos]"/>;
                        align:center
                    }
                   </xsl:for-each>
                </style>
            </head>                
            <body>
                <table>
                    <tr>
                        <xsl:for-each select="/NewDataSet/defects[1]/*">
                            <th>
                                <xsl:value-of select="name(.)"/>
                            </th>
                        </xsl:for-each>
                    </tr>
                    <xsl:apply-templates select="*"/>
                </table>
            </body>
        </html>
   </xsl:template>

    <xsl:template match="/NewDataSet/defects">
        <tr>
            <xsl:attribute name="class">testid<xsl:value-of select="testid"/></xsl:attribute>
            <xsl:for-each select="*">
                <td>
                    <xsl:value-of select="."/>
                </td>
            </xsl:for-each>
        </tr>
    </xsl:template>

</xsl:stylesheet>

I applied this on the below xml:

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <defects>
    <Defectid>56</Defectid>
    <testid>111</testid>
    <summary>Release of DIT </summary>
    <DetectedDate>2011-09-21 </DetectedDate>
    <priority>2-Give High Attention</priority>
    <status>Ready to Test</status>
    <project>Business Intelligence</project>
    <assignedTo>peter</assignedTo>
    <detectedBy>john</detectedBy>
    <severity>3-Average</severity>
  </defects>
  <defects>
    <Defectid>829</Defectid>
    <testid>111</testid>
    <summary> Data request</summary>
    <DetectedDate>2012-01-12 </DetectedDate>
    <priority>3-Normal Queue</priority>
    <status>Open</status>
    <project>web</project>
    <assignedTo>tcm</assignedTo>
    <detectedBy>john</detectedBy>
    <severity>3-Average</severity>
  </defects>
  <defects>
    <Defectid>728</Defectid>
    <testid>999</testid>
    <summary>Data request</summary>
    <DetectedDate>2012-01-11</DetectedDate>
    <priority>3-Normal Queue</priority>
    <status>Fixed</status>
    <project>Business Intelligence</project>
    <assignedTo>chris</assignedTo>
    <detectedBy>peter</detectedBy>
    <severity>3-Average</severity>
  </defects>
  <defects>
    <Defectid>728</Defectid>
    <testid>321</testid>
    <summary>Data request</summary>
    <DetectedDate>2012-01-11</DetectedDate>
    <priority>3-Normal Queue</priority>
    <status>Fixed</status>
    <project>Business Intelligence</project>
    <assignedTo>chris</assignedTo>
    <detectedBy>peter</detectedBy>
    <severity>3-Average</severity>
  </defects>
  <defects>
    <Defectid>728</Defectid>
    <testid>457</testid>
    <summary>Data request</summary>
    <DetectedDate>2012-01-11</DetectedDate>
    <priority>3-Normal Queue</priority>
    <status>Fixed</status>
    <project>Business Intelligence</project>
    <assignedTo>chris</assignedTo>
    <detectedBy>peter</detectedBy>
    <severity>3-Average</severity>
  </defects>
  <defects>
    <Defectid>728</Defectid>
    <testid>202</testid>
    <summary>Data request</summary>
    <DetectedDate>2012-01-11</DetectedDate>
    <priority>3-Normal Queue</priority>
    <status>Fixed</status>
    <project>Business Intelligence</project>
    <assignedTo>chris</assignedTo>
    <detectedBy>peter</detectedBy>
    <severity>3-Average</severity>
  </defects>
</NewDataSet>

And got as result

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <style>
                    th, td {
                        border: solid black 1px ;
                        padding: 3px;                       
                        border-spacing:2px;
                        border-collapse: collapse;
                        width: 100px;
                    }
                    th {
                        font-family:verdana;
                        font-size:60%;
                        color:green;
                        align:center;
                        white-space: nowrap;
                    }

                     tr.testid111 {
                        font-family:verdana;
                        font-size:60%;
                        font-weight:bold;
                        color:#0000FF;
                        align:center
                    }

                     tr.testid999 {
                        font-family:verdana;
                        font-size:60%;
                        font-weight:bold;
                        color:#FF0000;
                        align:center
                    }

                     tr.testid321 {
                        font-family:verdana;
                        font-size:60%;
                        font-weight:bold;
                        color:#00FFFF;
                        align:center
                    }

                     tr.testid457 {
                        font-family:verdana;
                        font-size:60%;
                        font-weight:bold;
                        color:#FFFF00;
                        align:center
                    }

                     tr.testid202 {
                        font-family:verdana;
                        font-size:60%;
                        font-weight:bold;
                        color:#347C2C;
                        align:center
                    }
                   </style>
    </head>
    <body>
        <table>
            <tr>
                <th>Defectid</th>
                <th>testid</th>
                <th>summary</th>
                <th>DetectedDate</th>
                <th>priority</th>
                <th>status</th>
                <th>project</th>
                <th>assignedTo</th>
                <th>detectedBy</th>
                <th>severity</th>
            </tr>
            <tr class="testid111">
                <td>56</td>
                <td>111</td>
                <td>Release of DIT </td>
                <td>2011-09-21 </td>
                <td>2-Give High Attention</td>
                <td>Ready to Test</td>
                <td>Business Intelligence</td>
                <td>peter</td>
                <td>john</td>
                <td>3-Average</td>
            </tr>
            <tr class="testid111">
                <td>829</td>
                <td>111</td>
                <td> Data request</td>
                <td>2012-01-12 </td>
                <td>3-Normal Queue</td>
                <td>Open</td>
                <td>web</td>
                <td>tcm</td>
                <td>john</td>
                <td>3-Average</td>
            </tr>
            <tr class="testid999">
                <td>728</td>
                <td>999</td>
                <td>Data request</td>
                <td>2012-01-11</td>
                <td>3-Normal Queue</td>
                <td>Fixed</td>
                <td>Business Intelligence</td>
                <td>chris</td>
                <td>peter</td>
                <td>3-Average</td>
            </tr>
            <tr class="testid321">
                <td>728</td>
                <td>321</td>
                <td>Data request</td>
                <td>2012-01-11</td>
                <td>3-Normal Queue</td>
                <td>Fixed</td>
                <td>Business Intelligence</td>
                <td>chris</td>
                <td>peter</td>
                <td>3-Average</td>
            </tr>
            <tr class="testid457">
                <td>728</td>
                <td>457</td>
                <td>Data request</td>
                <td>2012-01-11</td>
                <td>3-Normal Queue</td>
                <td>Fixed</td>
                <td>Business Intelligence</td>
                <td>chris</td>
                <td>peter</td>
                <td>3-Average</td>
            </tr>
            <tr class="testid202">
                <td>728</td>
                <td>202</td>
                <td>Data request</td>
                <td>2012-01-11</td>
                <td>3-Normal Queue</td>
                <td>Fixed</td>
                <td>Business Intelligence</td>
                <td>chris</td>
                <td>peter</td>
                <td>3-Average</td>
            </tr>
        </table>
    </body>
</html>

which in a browser looks as follows:

table view

ADDED variant using key

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:std="http://www.standardColors.com"
    exclude-result-prefixes="std">

    <xsl:output method="html"/>

    <xsl:variable name="colors">
        <color>#0000FF</color>
        <color>#FF0000</color>
        <color>#00FFFF</color>
        <color>#FFFF00</color>
        <color>#347C2C</color>
        <color>#800080</color>
        <color>#3B9C9C</color>
        <color>#A52A2A</color>
        <color>#3BB9FF</color>
        <color>#FF00FF</color>
        <color>#6698FF</color>
        <color>#808000</color>
        <color>#8D38C9</color>
        <color>#ADD8E6</color>
        <color>#F660AB</color>
        <color>#F87217</color>
        <color>#F9B7FF</color>
        <color>#FFA500</color>
        <color>#FFE87C</color>
        <color>#8E35EF</color>
    </xsl:variable>

    <!--<xsl:variable name="testIDs" select="distinct-values(//testid)"/>-->

    <xsl:key name="testidKey" match="testid" use="text()"/>

    <xsl:variable name="colorList">
        <xsl:for-each select="//testid">
            <xsl:if test="generate-id() = generate-id(key('testidKey', text())[1])">
                <xsl:variable name="pos" select="position() mod 20"/>
                <color>
                    <xsl:attribute name="testid"><xsl:value-of select="."/></xsl:attribute>
                    <xsl:value-of select="$colors/color[$pos]"/>
                </color>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>

    <xsl:template match="/">
        <html>
            <head>
                <style>
                    th, td {
                        border: solid black 1px ;
                        padding: 3px;                       
                        border-spacing:2px;
                        border-collapse: collapse;
                        width: 100px;
                    }
                    th {
                        font-family:verdana;
                        font-size:60%;
                        color:green;
                        align:center;
                        white-space: nowrap;
                    }
                    <xsl:for-each select="$colorList/color">
                     tr.testid<xsl:value-of select="@testid"/> {
                        font-family:verdana;
                        font-size:60%;
                        font-weight:bold;
                        color:<xsl:value-of select="."/>;
                        align:center
                    }
                   </xsl:for-each>
                </style>
            </head>                
            <body>
                <table>
                    <tr>
                        <xsl:for-each select="/NewDataSet/defects[1]/*">
                            <th>
                                <xsl:value-of select="name(.)"/>
                            </th>
                        </xsl:for-each>
                    </tr>
                    <xsl:apply-templates select="*"/>
                </table>
            </body>
        </html>
   </xsl:template>

    <xsl:template match="/NewDataSet/defects">
        <tr>
            <xsl:attribute name="class">testid<xsl:value-of select="testid"/></xsl:attribute>
            <xsl:for-each select="*">
                <td>
                    <xsl:value-of select="."/>
                </td>
            </xsl:for-each>
        </tr>
    </xsl:template>

</xsl:stylesheet>

MSXML error prevention (and any other xsl engine used)

see convert RTF into node-set and RTF to node-set generic approach for further details.

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:std="http://www.standardColors.com"
    xmlns:exslt="http://www.exslt.org/common"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="std">

    <xsl:output method="html"/>

    <std:colors>
        <color>#0000FF</color>
        <color>#FF0000</color>
        <color>#00FFFF</color>
        <color>#FFFF00</color>
        <color>#347C2C</color>
        <color>#800080</color>
        <color>#3B9C9C</color>
        <color>#A52A2A</color>
        <color>#3BB9FF</color>
        <color>#FF00FF</color>
        <color>#6698FF</color>
        <color>#808000</color>
        <color>#8D38C9</color>
        <color>#ADD8E6</color>
        <color>#F660AB</color>
        <color>#F87217</color>
        <color>#F9B7FF</color>
        <color>#FFA500</color>
        <color>#FFE87C</color>
        <color>#8E35EF</color>
    </std:colors>

    <xsl:variable name="colors" select="document('')/*/std:colors"/>

    <xsl:key name="testidKey" match="testid" use="text()"/>

    <xsl:variable name="std:colorList">
        <xsl:for-each select="//testid">
            <xsl:if test="generate-id() = generate-id(key('testidKey', text())[1])">
                <xsl:variable name="pos" select="position() mod 20"/>
                <xsl:element name="color">
                    <xsl:attribute name="testid"><xsl:value-of select="."/></xsl:attribute>
                    <xsl:value-of select="$colors/color[$pos + 1]"/>
                </xsl:element>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>

    <xsl:template match="/">
        <html>
            <head>
                <style>
                    table {
                        font-family:verdana;
                        font-size:60%;
                        font-weight:bold;
                        align:center;
                        white-space: nowrap;
                    }
                    th, td {
                        border: solid black 1px ;
                        padding: 3px;                       
                        border-spacing:2px;
                        border-collapse: collapse;
                        width: 100px;
                    }
                    th {
                        color:green;
                    }
                    <xsl:choose>
                        <xsl:when test="function-available('msxsl:node-set')">
                            <xsl:apply-templates select="msxsl:node-set($std:colorList)/color" mode="addTRclassToCSS"/>
                        </xsl:when>
                        <xsl:when test="function-available('exslt:node-set')">
                            <xsl:apply-templates select="exslt:node-set($std:colorList)/color" mode="addTRclassToCSS"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:variable name="colorList" select="$std:colorList"/>
                            <xsl:apply-templates select="$colorList" mode="addTRclassToCSS"/>
                        </xsl:otherwise>
                    </xsl:choose>

                </style>
            </head>                
            <body>
                <table>
                    <tr>
                        <xsl:for-each select="/NewDataSet/defects[1]/*">
                            <th>
                                <xsl:value-of select="name(.)"/>
                            </th>
                        </xsl:for-each>
                    </tr>
                    <xsl:apply-templates select="*"/>
                </table>
            </body>
        </html>
   </xsl:template>

    <xsl:template match="/NewDataSet/defects">
        <tr>
            <xsl:attribute name="class">testid<xsl:value-of select="testid"/></xsl:attribute>
            <xsl:for-each select="*">
                <td>
                    <xsl:value-of select="."/>
                </td>
            </xsl:for-each>
        </tr>
    </xsl:template>

    <xsl:template match="color" mode="addTRclassToCSS">
                    tr.testid<xsl:value-of select="@testid"/> {
                    color:<xsl:value-of select="."/>;
                    }
    </xsl:template>
</xsl:stylesheet>

Waht is the best way to automatically generate junit results in xml?

4 votes

I am currently writing a series of tests in JUnit. I need to automatically export the results as XML. I was reading that the best way of doing this is by extending the RunListener class and writing the XML that way. Below is a sample of what I have done so far, but I am struggling with how to extract information on each test that has been run. The 'Description' class doesn't seem to have any useful get methods and I feel like I am maybe going about this the wrong way.

Can someone assist with how to get useful information from description (eg. test passed / failed, duration of test, test name etc) or give me some advice on what I actually should be doing?

Thanks

public class XmlListener extends RunListener {

    private final PrintStream fWriter;

    public XmlListener(JUnitSystem system) {
        this(system.out());
    }

    public XmlListener(PrintStream writer) {
        this.fWriter = writer;
    }

    @Override
    public void testRunStarted(Description description) {
        fWriter.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
    }

    @Override
    public void testRunFinished(Result result) {
        fWriter.append("\t\t</suite>\n");
        fWriter.append("\t</suites>\n");
        fWriter.append("</result>\n");
        printHeader(result.getRunTime());
        printFailures(result);
        printFooter(result);

    }

    @Override
    public void testStarted(Description description) {
        fWriter.append("\t\t\t<case>\n");
        fWriter.append("\t\t\t\t<timestamp>"  + "</timestamp>\n");
        fWriter.append("\t\t\t\t<className>"  + "</className>\n");
        fWriter.append("\t\t\t\t<testName>"  + "</testName>\n");
    }

    @Override
    public void testFinished(Description description) {
        fWriter.append("\t\t\t\t<duration>"  + "</duration>\n");
        fWriter.append("\t\t\t</case>\n");
        Iterator it = description.getAnnotations().iterator();
        while (it.hasNext()) {
            fWriter.append(it.next().toString());
        }
    }

    @Override
    public void testFailure(Failure failure) {
        fWriter.append('E');
    }

    @Override
    public void testIgnored(Description description) {
        fWriter.append('I');
    }

    /**
     * private methods
     * @return
     */

    private PrintStream getWriter() {
        return fWriter;
    }

    protected void printHeader(long runTime) {
        getWriter().println();
        getWriter().println("Time: " + elapsedTimeAsString(runTime));
    }

    protected void printFailures(Result result) {
        List<Failure> failures= result.getFailures();
        if (failures.size() == 0)
            return;
        if (failures.size() == 1)
            getWriter().println("There was " + failures.size() + " failure:");
        else
            getWriter().println("There were " + failures.size() + " failures:");
        int i= 1;
        for (Failure each : failures)
            printFailure(each, "" + i++);
    }

    protected void printFailure(Failure each, String prefix) {
        getWriter().println(prefix + ") " + each.getTestHeader());
        getWriter().print(each.getTrace());
    }

    protected void printFooter(Result result) {
        if (result.wasSuccessful()) {
            getWriter().println();
            getWriter().println("\t</suites>\n");
            getWriter().println("</result>\n");
            getWriter().println(" (" + result.getRunCount() + " test" + (result.getRunCount() == 1 ? "" : "s") + ")");

        } else {
            getWriter().println();
            getWriter().println("FAILURES!!!");
            getWriter().println("Tests run: " + result.getRunCount() + ",  Failures: " + result.getFailureCount());
        }
        getWriter().println();
    }

    /**
     * Returns the formatted string of the elapsed time. Duplicated from
     * BaseTestRunner. Fix it.
     */
    protected String elapsedTimeAsString(long runTime) {
        return NumberFormat.getInstance().format((double) runTime / 1000);
    }
}

UPDATE - Ant build file

<?xml version="1.0" encoding="UTF-8"?>
<project name="COTPlus" default="main" basedir=".">
<property name="src.dir" location="src" />

<target name="test" >
<junit printsummary="on" haltonfailure="false">
  <formatter type="xml" />
  <batchtest todir="/test-reports">
    <fileset dir="${src.dir}" includes="**/ExampleTest.java"  />
  </batchtest>
</junit>
</target>

<target name="main" depends="test">
        <description>Main target</description>
        <echo>${src.dir}</echo>
    </target>

</project>

You can use a Ant Script to get XML Results

<target name="test" >

 <javac srcdir="/src"
     destdir="/bin"
     classpath="/lib/junit.jar"  />


<junit haltonfailure="false">
  <formatter type="xml" />
  <batchtest todir="/test-reports">
    <fileset dir="/bin" includes="tests/ExampleTest.class"  />
  </batchtest>
</junit>
</target>

this will Generate an xml into the /test-reports Folder. More Details on Ant Builds http://ant.apache.org/manual/tasksoverview.html

jQuery multiple selectors with dot notation?

4 votes

OK. I'm somewhat of a noob... but not that noob-ish. :)

I desire to accomplish a find() in jQuery that has a similar result of dot notation or "&&". Here is an example (which does not work):

data.find("continent_country[id = 'us'].state[id = 'in']").each(function(){
// what to do
}

or

data.find("continent_country[id = 'us'] && state[id = 'in']").each(function(){
// what to do
}

I have been told to try a comma, like so:

data.find("continent_country[id = 'us'], state[id = 'in']").each(function(){
// what to do
}

... but that returns the wrong items.

My XML looks like this:

    <continent_country id="us" name="U.S.">
        <state id="al" name="Alabama"> 
            <city url="" name="auburn"/>
            <city url="" name="birmingham"/>
            <city url="" name="dothan"/>
            <city url="" name="florence / muscle shoals"/>
            <city url="" name="gadsden-anniston"/>
            <city url="" name="huntsville / decatur"/>
            <city url="" name="mobile"/>
            <city url="" name="montgomery"/>
            <city url="" name="tuscaloosa"/> 
        </state>
        <state>//more states</states>
    </continent_country>
    </continent_country id="eu" name="Europe">
        <state>//more states</states>
    </continent_country>

Some states/provinces/countries share the same id, which is why I would like to find a state in a specified continent_country.

Thanks in advance...

i think you want the child notation:

http://api.jquery.com/child-selector/

something like

data.find('continent_country[id = 'us'] > state[id='in']).each(function(){
   //do your stuff here
} 

SQL Server: OPENXML vs SELECT..FROM when dealing with XML?

4 votes

I have this xml :

DECLARE @x XML
SET @x = 
    '<data>
       <add>a</add>
       <add>b</add>
       <add>c</add>
     </data>';

Task :

I want to list the a,b,c.

approach 1 :

SELECT s.value('.', 'VARCHAR(8000)') AS [ADD]
FROM   @x.nodes('/data/add') AS t(s) 

approach 2:

DECLARE @idoc INT
EXEC sp_xml_preparedocument @idoc OUTPUT, @x

SELECT *
FROM   OPENXML(@idoc, '/data/add', 2)
       WITH ([add] NVARCHAR(MAX) '.')

both of them give me :

enter image description here

question :

which is the preferred way ?

Is there any advantages of the latter vs former ( or vice verse) ?

A simple test shows that your approach 1 takes less time than approach 2. I would not draw any conclusions about it always being the case. It can depend on how your XML is structured and how you need to query the XML.

Stored procedures to test on:

create procedure TestXML
  @X xml
as
set nocount on

select X.N.value('.', 'varchar(8000)')
from @X.nodes('/root/item') as X(N)

go

create procedure TestOpenXML
  @X xml
as
set nocount on

declare @idoc int
exec sp_xml_preparedocument @idoc out, @X

select value
from openxml(@idoc, '/root/item',1) 
  with (value  varchar(8000) '.')

exec sp_xml_removedocument @idoc

Test:

declare @X xml

set @X =
  (
    select number as '*'
    from master..spt_values
    for xml path('item'), root('root'), type
  )

set statistics time on
exec TestXML @X
exec TestOpenXML @X

Result approach 1:

SQL Server Execution Times:
   CPU time = 63 ms,  elapsed time = 70 ms.

Result approach 2:

SQL Server Execution Times:
   CPU time = 156 ms,  elapsed time = 159 ms.

(Tested on SQL Server 2005.)

XML Data Type In SQL Server 2008 Query

4 votes

I have a table in SQL Server in which one of the columns is an XML Datatype. There are other columns in the table that are not XML. Here is an example of the XML that is stored in the column:

<AdultAsthma>
  <Group>
    <Question text="Act Score:" ForeColor="Green" />
    <Controls>
      <Control type="Label" id="txtScore" text="Enter ACT Score:" ForeColor="Black" />
      <Control type="TextBox" id="txtActScore" Answer="" />
    </Controls>
  </Group>
</AdultAsthma>

What I want is a query that matches some values on the other columns in the table and for those columns that match, I want to get the text attribute from the Question Node and the Answer attribute from the Control node. Can someone help me with this?

EDIT

What needs to be changed if I have more than one Group node? In this scenerio, I would want the text of each question and the answer to go along with each question. See below:

<AdultAsthma>
  <Group>
    <Question text="Act Score:" ForeColor="Green" />
    <Controls>
      <Control type="Label" id="txtScore" text="Enter ACT Score:" ForeColor="Black" />
      <Control type="TextBox" id="txtActScore" Answer="" />
    </Controls>
  </Group>
  <Group>
    <Question text="Do You Have Asthma?:" ForeColor="Black" />
    <Controls>
      <Control type="RadioButton" id="rbHaveAsthmaYes" text="Yes" GroupName="Diagnosed" ForeColor="Black" Answer="False" />
      <Control type="RadioButton" id="rbHaveAsthmaNo" text="No" GroupName="Diagnosed" ForeColor="Black" Answer="False" />
    </Controls>
  </Group>
</AdultAsthma>

declare @T table
(
  XMLCol xml
)

insert into @T values
('<AdultAsthma>
  <Group>
    <Question text="Act Score:" ForeColor="Green" />
    <Controls>
      <Control type="Label" id="txtScore" text="Enter ACT Score:" ForeColor="Black"/>
      <Control type="TextBox" id="txtActScore" Answer="Answer" />
    </Controls>
  </Group>
</AdultAsthma>
')

select XMLCol.value(N'(/AdultAsthma/Group/Question/@text)[1]', 'nvarchar(max)'),
       XMLCol.value(N'(/AdultAsthma/Group/Controls/Control/@Answer)[1]', 'nvarchar(max)')
from @T

Update:

When you need to shred your XML to multiple rows you can use .nodes() in a cross apply.

declare @T table
(
  XMLCol xml
)

insert into @T values
('<AdultAsthma>
  <Group>
    <Question text="Act Score:" ForeColor="Green" />
    <Controls>
      <Control type="Label" id="txtScore" text="Enter ACT Score:" ForeColor="Black" />
      <Control type="TextBox" id="txtActScore" Answer="" />
    </Controls>
  </Group>
  <Group>
    <Question text="Do You Have Asthma?:" ForeColor="Black" />
    <Controls>
      <Control type="RadioButton" id="rbHaveAsthmaYes" text="Yes" GroupName="Diagnosed" ForeColor="Black" Answer="False" />
      <Control type="RadioButton" id="rbHaveAsthmaNo" text="No" GroupName="Diagnosed" ForeColor="Black" Answer="False" />
    </Controls>
  </Group>
</AdultAsthma>
')

select X.N.value(N'(Question/@text)[1]', 'nvarchar(max)'),
       X.N.value(N'(Controls/Control/@Answer)[1]', 'nvarchar(max)')
from @T as T
  cross apply T.XMLCol.nodes(N'/AdultAsthma/Group') as X(N)

XSLT Concat fields together

4 votes

i am trying to filter on a specific field and concat on another field:

Input:

<?xml version="1.0" encoding="UTF-8"?>
<payloads>
    <payload>
        <firstname>michael</firstname>
        <secondname>brown</secondname>
        <number>1</number>
    </payload>
    <payload>
        <firstname>michael</firstname>
        <secondname>brown</secondname>
        <number>2</number>
    </payload>
    <payload>
        <firstname>michael</firstname>
        <secondname>brown</secondname>
        <number>3</number>
    </payload>
</payloads>

Output:

<?xml version="1.0" encoding="UTF-8"?>
<payloads>
    <payload>
        <firstname>michael</firstname>
        <secondname>brown</secondname>
        <number>1,2,3</number>
    </payload>
</payloads>

I know that i need to loop through each payload tag, but at the moment i am unable to get it too output correctly. At the moment i have this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="payloads">
        <xsl:copy>
            <xsl:for-each select="payload">
                <payload>
                    <xsl:value-of select="firstname"/>
                    <xsl:value-of select="secondname"/>
                    <xsl:value-of select="number"/>
                </payload>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Use this template:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="k" match="payload" use="concat(firstname, '|', secondname)"/>

    <xsl:template match="payload[generate-id() = 
                  generate-id(key('k', concat(firstname, '|', secondname)))]">
        <xsl:copy>
            <xsl:copy-of select="firstname"/>
            <xsl:copy-of select="secondname"/>
            <number>
                <xsl:for-each select="key('k', concat(firstname, '|', secondname))">
                    <xsl:value-of select="number"/>

                    <xsl:if test="position() != last()">
                        <xsl:text>,</xsl:text>
                    </xsl:if>
                </xsl:for-each>
            </number>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="payload"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

When applied to provided input XML, it outputs wanted correct result:

<payloads>
  <payload>
    <firstname>michael</firstname>
    <secondname>brown</secondname>
    <number>1,2,3</number>
  </payload>
</payloads>

How to map xml (objects) to methods in Objective-C?

4 votes

I have an xml file that contains a structure.. In this structure, I have Actions node. So under Actions node, there are multiple "Action" nodes that each has Value and Name attributes.

e.g.

<?xml version="1.0" encoding="ISO-8859-1"?>

<Testcases SuiteName="CalculatorActions">

    <Testcase id="101" Name="testAddFunction">
        <Setup/>
        <TearDown/>
        <Test>
            <Action Name="Enter first operand" Type="input" Value="5"/>
            <Action Name="Enter second operand" Type="input" Value="3"/>
            <Action Name="Select operator" Type="input" Value="+"/>
            <Action Name="Click Calculator" Type="operation"/>
        </Test>
        <Validations>
            <Action Name="Validate result" Type="output" Value="8"/>
        </Validations>
    </Testcase>

</Testcases>

What I would like to do is; I want to map these actions to the methods that I have implemented in Objective-C.

Let's say i have a class called; "CalculatorActions" and defined 5 methods inside. I would like to map the actions that i have in xml (text format) to the methods i created in CalculatorActions.

e.g.

@interface CalculatorActions : NSObject

// Property
@property (strong, nonatomic) NSString* actionScript;

// Actions
- (void)enterFirstOperand:(double)operand;

- (void)enterSecondOperand:(double)operand;

- (void)selectOperator:(NSString*)operator;

- (void)clickCalculate;

// Validations

-(void)validateResult:(NSString*)exptectedResult;

@end

so when i read the xml file, I would want to map the actions in xml file to the corresponding method in a class.

I think what i am looking for is something like;

@interface CalculatorActions

[Action("addOperand", "Enter first operand")]
- (void) addOperand:(double)operand1 ToOther:(double)operand2;

What would be the best way to do this?

You can create an NSInvocation instance, set the selector, arguments, and optionally capture the return value. You can create these all with strings.

e.g.

SEL mySelector = NSSelectorFromString(@"testAddFunction");
Class MyClass = NSClassFromString(@"CalculatorActions");
NSString *myArgument = @"5";

NSInvocation *myInvocation = [NSInvocation invocationWithMethodSignature:[MyClass instanceMethodSignatureForSelector:mySelector]];
[invocation setTarget:myClass];
[invocation setSelector:mySelector];
[invocation setArgument:&myArgument atIndex:2];
[invocation invoke];

Note - the setArgument: selector takes a pointer address, and the index of the arguments start at 2.

What is the fastest way to write XML file withsome logic in C#

4 votes

I want to write a xml file with C#. It is a basic file like that :

<EmployeeConfiguration>
  <Bosses>
    <Boss name="BOB">
      <Employees>
        <Employee Id="#0001" />
        <Employee Id="#0002" />
      </Employees>
    <Boss>
  </Bosses>
</EmployeeConfiguration>

and I don't want have an Employees node if there is not Employee node...

I want use XElement but I can't because of that... So I used XmlWriter. it works fine but I find it's very verbose to write XML :

EmployeeConfiguration config = EmployeeConfiguration.GetConfiguration();

using (XmlWriter writer = XmlWriter.Create(_fileUri, settings))
{
  writer.WriteStartDocument();

  // <EmployeeConfiguration>
  writer.WriteStartElement("EmployeeConfiguration");

  if (config.Bosses.Count > 0)
  {
    // <Bosses>
    writer.WriteStartElement("Bosses");

    foreach (Boss b in config.Bosses)
    {
      // Boss
      writer.WriteStartElement("Boss");
      writer.WriteStartAttribute("name");
      writer.WriteString(b.Name);
      writer.WriteEndAttribute();

      if (b.Employees.Count > 0)
      {
        writer.WriteStartElement("Employees");

        foreach (Employee emp in b.Employees)
        {
            writer.WriteStartElement(Employee);
            writer.WriteStartAttribute(Id);
            writer.WriteString(emp.Id);
            writer.WriteEndAttribute();
            writer.WriteEndElement();
        }
      }
    }
  }
}

Is there another (and fastest) way to write this kind of xml file ?

If you mean "fastest" as the fastest way to write some code to do it (and the simplest), then creating a custom class and serializing it using the XmlSerializer is the way to go...

Create your classes as follows:

[XmlRoot("EmployeeConfiguration")]
public class EmployeeConfiguration
{
    [XmlArray("Bosses")]
    [XmlArrayItem("Boss")]
    public List<Boss> Bosses { get; set; }
}

public class Boss
{
    [XmlAttribute("name")]
    public string Name { get; set; }

    [XmlArray("Employees")]
    [XmlArrayItem("Employee")]
    public List<Employee> Employees { get; set; }
}

public class Employee
{
    [XmlAttribute]
    public string Id { get; set; }
}

and then you can serialize these out with this:

// create a serializer for the root type above
var serializer = new XmlSerializer(typeof (EmployeeConfiguration));

// by default, the serializer will write out the "xsi" and "xsd" namespaces to any output.
// you don't want these, so this will inhibit it.
var namespaces = new XmlSerializerNamespaces(new [] { new XmlQualifiedName("", "") });

// serialize to stream or writer
serializer.Serialize(outputStreamOrWriter, config, namespaces);

As you can see - using various attributes on the classes instruct the serializer in how it should serialize the class. Some of the ones I've included above are actually the default settings and don't explicitly need to be stated - but I've included them to show you how it is done.

serialise bool? error reflecting type

4 votes

i have a class like

   [Serializable]
    public class MyClass
    {
        [XmlAttribute]
        public bool myBool { get; set; }
    }

But this serializes the value of the bool to false when the attribute is not present in the xml. When the attribute is not in the xml I want the property to be null.

So i tried this

[Serializable]
public class MyClass
{
    [XmlAttribute]
    public bool? myBool { get; set; }
}

But then the serializer errors

Type t = Type.GetType("Assembly.NameSpace.MyClass");
                XmlSerializer mySerializer = new XmlSerializer(t); //error "There was an error reflecting type"

Please give me a example of i can do this. I know there are some related questions on SO but nothing that shows how to overcome the reflection error with a nullable bool. Thanks.

You need to use the "*Specified" field pattern to control this (see "Controlling Generated XML" on MSDN):

[Serializable]
public class MyClass
{
    [XmlAttribute]
    public bool myBool { get; set; }

    [XmlIgnore]
    public bool myBoolSpecified;
}

The logic now becomes:

  • If !myBoolSpecified, then myBool is logically null
  • Else use the true or false of myBool