Bibliography & Citations 102 – Building Custom styles

My name is Nathan Kwan. I am a PM intern on the Microsoft Word team. My internship started in early January and is sadly coming to an end at the end of April. I'm a 4th year student at the University of Waterloo working towards my Software Engineering degree.

When I started on the team, I was given the bibliography feature. Being a student myself, I am a fan, so I was pretty excited to dig into it.

What will this post cover?

In Amani's last post, she showed you how to setup and build a simple bibliography style. We learned that bibliography styles in Word are XSLTs. We also found that we could drop our own custom styles in C:\Program Files\Microsoft Office\Office12\Bibliography\Style and Word will display them.

Today, I'm going to be expanding on Amani's post to show you how to build more complex styles. One of the issues that "complicates" bibliography styles is that they often need to have a significant amount of conditional logic built into them. For example, if the date is specified we need to show the date, whereas if the date is not specified we may need to use an abbreviation to indicate that there is no date for that source.

For a more specific example, in the APA style, if a date is not specified for a website source, then the abbreviation n.d. is used to denote no date…and the style should do this automatically. The example is shown below:

APA website source with no date entered:

Kwan, N. (n.d.). Retrieved from www.microsoft.com

APA website source with date entered:

Kwan, N. (2006, Jan 18). Retrieved from www.microsoft.com

As you can see, what is displayed is conditional on the data entered.

Unfortunately, there is not enough space or time in this blog to go through each and every rule that a new style would need, but I will provide a foundation for you to create new styles by showing you step by step how to implement a single rule that leverages conditional logic.

The rule I will be showing is one of the most common rules. The output of virtually every style needs to change depending on whether you have a "Corporate Author" or a "Normal Author".

I'm going to show you how to display a corporate author if the corporate author is specified and display a normal author if the corporate author is not specified.

Overview of Solution

To display a corporate author only if it is filled in, we need to take the following actions:

  1. Add a variable to count the number of corporate authors in the citation section of the code
  2. Display the corporate author in the citation if the corporate author is filled in. Display the normal author in the citation if the corporate author is not filled in.
  3. Add a variable to count the number of corporate authors in the bibliography section of the code
  4. Display the corporate author in the bibliography if the corporate author is filled in. Display the normal author in the bibliography if the corporate author is not filled in.

Getting Started


Let's start by changing the citation. This is the code for citations from last time:

<!-- Defines the output of the Citation -->

<xsl:template match="b:Citation/b:Source[b:SourceType = 'Book']">

<html xmlns="http://www.w3.org/TR/REC-html40">

<body>

<!-- Defines the output format as (Author, Year)-->

<xsl:text>(</xsl:text>

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:Last"/>

<xsl:text>, </xsl:text>

<xsl:value-of select="b:Year"/>

<xsl:text>)</xsl:text>

</body>

</html>

</xsl:template>

......

    

Step 1: Define a new variable in the citation section to count the number of Corporate Authors

We'll need to be declaring a new variable to help us determine whether a corporate author is available. This variable is a count on the number of times the corporate author field exists in our source.

<!-- Defines the output of the Citation -->

<html xmlns="http://www.w3.org/TR/REC-html40">

<!--Count the number of Corporate Authors (can only be 0 or 1)-->

<xsl:variable name="cCorporateAuthors">

<xsl:value-of select="count(b:Author/b:Author/b:Corporate)" />

</xsl:variable>

......

Step 2: Check to see whether the corporate author has been filled in

Now that we have this new variable, we need to check if the corporate author has been filled in. We can do this by checking if the count on corporate authors is not zero. If a corporate author exists, display it. If it does not exist, display the normal author.

......

<xsl:text>(</xsl:text>

<xsl:choose>

<!--when the corporate author exists display the corporate author-->

<xsl:when test ="$cCorporateAuthors!=0">

<xsl:value-of select="b:Author/b:Author/b:Corporate"/>

</xsl:when>

<!-- when the corporate author does not exist, display the normal author-->

<xsl:otherwise>

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:Last"/>

</xsl:otherwise>

</xsl:choose>

<xsl:text>, </xsl:text>

.......

Now that we made the change for citations, let's make the change for our bibliography. Here's the bibliography section from the original post:

......

<!-- Defines the output format for a simple Book (in the Bibliography) with important fields defined -->

<xsl: template match="b:Source[b:SourceType = 'Book']">

<!--Label the paragraph as an Office Bibliography paragraph -->

<p>

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:Last"/>

<xsl:text>, </xsl:text>

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:First"/>

<xsl:text>. (</xsl:text>

<xsl:value-of select="b:Year"/>

<xsl:text>). </xsl:text>

<i>

......

Step 3: Define a new variable in the bibliography section

Once again, let's start by adding a counting variable.

......

<!-- Defines the output format for a simple Book (in the Bibliography) with important fields defined -->

<xsl: template match="b:Source[b:SourceType = 'Book']">

<! --Count the number of Corporate Authors (can only be 0 or 1)-->

<xsl:variable name="cCorporateAuthors">

<xsl:value-of select="count(b:Author/b:Author/b:Corporate)" />

</xsl:variable>

......

Step 4: Check to see whether the corporate author has been filled in

Now let's add the check to see if a corporate author exists.

......

<xsl:variable name="cCorporateAuthors">

<xsl:value-of select="count(b:Author/b:Author/b:Corporate)" />

</xsl:variable>

<p>

<xsl:choose>

<!--when the corporate author exists display the corporate author-->

<xsl:when test ="$cCorporateAuthors!=0">

<xsl:value-of select="b:Author/b:Author/b:Corporate"/>

<xsl:text>. (</xsl:text>

</xsl:when>

<xsl:otherwise>

<!-- when the corporate author does not exist, display the normal author -->

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:Last"/>

<xsl:text>, </xsl:text>

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:First"/>

<xsl:text>. (</xsl:text>

</xsl:otherwise>

</xsl:choose>

......

End Result

Now when we use a corporate author, it displays correctly in both our citation and bibliography!

This technique can be extended to perform any conditional statement we may need in our style.

Here's the final code that was used:

<?xml version="1.0" ?>

<!-- List of the external resources that we are referencing -->

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:b="http://schemas.openxmlformats.org/officeDocument/2006/bibliography">

<!-- When the bibliography or citation is in your document, it's just HTML -->

<xsl:output method="html" encoding="us-ascii"/>

<!-- match the root element, and dispatch to its children -->

<xsl:template match="/">

<xsl:apply-templates select="*" />

</xsl:template>

<!--set an optional version number for this style-->

<xsl:template match="b:version">

<xsl:text>2006.5.07</xsl:text>

</xsl:template>

<!-- Defines the name of the style in the References dropdown -->

<xsl:template match="b:StyleName">

<xsl:text>Simple Book Style</xsl:text>

</xsl:template>

<!-- Specifies which fields should appear in the Create Source dialog when in a collapsed state (The Show All Bibliography Fieldscheckbox is cleared) -->

<xsl:template match="b:GetImportantFields[b:SourceType = 'Book']">

<b:ImportantFields>

<b:ImportantField>

<xsl:text>b:Author/b:Author/b:NameList</xsl:text>

</b:ImportantField>

<b:ImportantField>

<xsl:text>b:Title</xsl:text>

</b:ImportantField>

<b:ImportantField>

<xsl:text>b:Year</xsl:text>

</b:ImportantField>

<b:ImportantField>

<xsl:text>b:City</xsl:text>

</b:ImportantField>

<b:ImportantField>

<xsl:text>b:Publisher</xsl:text>

</b:ImportantField>

</b:ImportantFields>

</xsl:template>

<!-- Defines the output format for a simple Book (in the Bibliography) with important fields defined -->

<xsl:template match="b:Source[b:SourceType = 'Book']">

<!--Count the number of Corporate Authors (can only be 0 or 1)-->

<xsl:variable name="cCorporateAuthors">

<xsl:value-of select="count(b:Author/b:Author/b:Corporate)" />

</xsl:variable>

<!--Label the paragraph as an Office Bibliography paragraph -->

<p>

<xsl:choose>

<xsl:when test ="$cCorporateAuthors!=0">

<!-- when the corporate author exists display the corporate author-->

<xsl:value-of select="b:Author/b:Author/b:Corporate"/>

<xsl:text>. (</xsl:text>

</xsl:when>

<xsl:otherwise>

<!-- when the corporate author does not exist, display the normal author-->

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:Last"/>

<xsl:text>, </xsl:text>

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:First"/>

<xsl:text>. (</xsl:text>

</xsl:otherwise>

</xsl:choose>

<xsl:value-of select="b:Year"/>

<xsl:text>). </xsl:text>

<i>

<xsl:value-of select="b:Title"/>

<xsl:text>. </xsl:text>

</i>

<xsl:value-of select="b:City"/>

<xsl:text>: </xsl:text>

<xsl:value-of select="b:Publisher"/>

<xsl:text>.</xsl:text>

</p>

</xsl:template>

<!-- Defines the output of the entire Bibliography -->

<xsl:template match="b:Bibliography">

<html xmlns="http://www.w3.org/TR/REC-html40">

<body>

<xsl:apply-templates select ="*">

</xsl:apply-templates>

</body>

</html>

</xsl:template>

<!-- Defines the output of the Citation -->

<xsl:template match="b:Citation/b:Source[b:SourceType = 'Book']">

<html xmlns="http://www.w3.org/TR/REC-html40">

<xsl:variable name="cCorporateAuthors">

<xsl:value-of select="count(b:Author/b:Author/b:Corporate)" />

</xsl:variable>

<body>    

<!-- Defines the output format as (Author, Year)-->

<xsl:text>(</xsl:text>

<xsl:choose>

<!-- when the corporate author exists display the corporate author-->

<xsl:when test ="$cCorporateAuthors!=0">

<xsl:value-of select="b:Author/b:Author/b:Corporate"/>

</xsl:when>

<!-- when the corporate author does not exist, display the normal author-->

<xsl:otherwise>

<xsl:value-of select="b:Author/b:Author/b:NameList/b:Person/b:Last"/>

</xsl:otherwise>

</xsl:choose>

<xsl:text>, </xsl:text>

<xsl:value-of select="b:Year"/>

<xsl:text>)</xsl:text>

</body>

</html>

</xsl:template>

<xsl:template match="text()" />

</xsl:stylesheet>

In conclusion, we built off of Amani's post to build a more complex style using conditional statements. The unfortunately reality is that bibliography styles are complex, but as this example shows, implementing the individual rule does not have to be.

-Nathan

Office Blogs Comments

Comments: (18) Collapse

  • It is great to finally see a follow-up post on this subject. I have a remark though. You are using elements such as "b:Author/b:Author/b:NameList/b:Person/b:Last" without giving any clue as to where you got them. I had to retrieve the 'official' format from the open xml specification, but I doubt many people will look that hard for it. So a listing of the elements would be nice. Some questions that remain: 1)What is the definition of the "SameAuthor", "MinAuthor", and "RepeatedAuthor" elements? Word calculates them internally, but without knowing what they represent, it is hard to use them. 2)Do the above elements (question 1) take into account that the 'author' is not always the Author? For example: Interview -> b:Interviewer, Art -> b:Artist, Book -> b:Author. 3)Can a characterstyle be directly applied to in-text citations from within the xslt? I mean, bibliographies get the MsoBibliography paragraph style applied to them. Can in-text citations get a similar MsoCitation character style applied to them? If so, what is its name? Right now it seems an in-text citation inherits its 'surrounding' style making it 'hard' to create superscript in-text citations for example. 4)Is there a(n undocumented) flag to indicate if an in-text citation should be of a different form? Basically, how can you differentiate between: a)Darwin (1859) wrote that ...

    b)... known as turtles (Darwin, 1859). Any answers would be great, even if it is just an 'It can't be done.' Yves

  • It would be very useful if Microsoft includes a tool for developing styles in word. So, I could configure a ABNT (Brazilian Academic Style), as I do need to make my doctor's thesis. Microsoft coulda do a specific style for use in Brazil; thanks,

  • Ok. That's pretty good. So, lets say, here in Brazil, according to the norm NBR 6023 of ABNT (Brazilian Association of Technical Norms), if it's not possible to determine when exactly the source was published (for instance), we should write the date between dashes; and if the place of publishing is unknown, we should write [S.l.], which means "sine loco". The same thing if the editor is unknown: we should write [S.n.], which means "sine nomine". How could the xsl script be made in this case? And there's another issue: this same norm dictates that there are two ways of citations: one that introduces indirect citation (the author's thoughts in our own words), and another one that is the normal citation, which is:(Author, Year), used when the citation is placed after the citated fragment. To the first type of citation, one should put the name of the authors off the parentesis. So, it would be like this: Author (Year). But there's one more problem: in this type of citation, we should also mention the page on which we can find the source of that specific fragment. So, in the end, it would be: Author (Year, page number). How could it be solved? Thanks

  • Romulo:

    You can extend the example to do exactly what you require. You can conditionally check if a user has specified any value by using the counting method above. When the count is zero, you know that the field has not been specified and you can add any special information you may need such as [S.n.] For example, you would add to count the publisher. You would then use the same method above to check whether cPublisher is zero and if so add [S.n.]. The second issue is a little bit more tricky. I hope this response will shed some light on Yves' question as well. When you use a citation you'll notice that there an edit citation button. When you click the edit citation button, you get a dialog box that allows you to suppress certain fields and add pages to the citation. You can once again conditionally display output depending on whether a tag exists or not. So you can display (Author, Year) when no fields are suppressed and then just (Year) when the author is suppressed. When you add pages or suppress an author through this dialog extra information is added to the source xml. Again, you'll have to use the same sort of conditional logic that we have in this example. For details on how this works, you can crack open the built in XSLT's which by default install at C:\Program Files\Microsoft Office\Office12\Bibliography\Style\. For example, I cracked open the Chicago style. I searched for noauthor and came up with the following code which conditionally displays the author depending if the noauthor flag is present. The noauthor flag is present when the author is supressed through the edit citation dialog. - - - You will be able to do something similar by having the citation display different outputs depending on whether the pages is specified and whether or not a field is suppressed. I hope that answers your questions. Good luck building your style!

  • Rômulo and Nathan:

    Using xslt's count() to check if data is available might not always work as it will also count empty elements ( ). I think it might be better to use string-length() or text() to verify that if the element exists, it actually has content. Nathan:

    No, the conditions do not solve my fourth question. I'm aware of the NoAuthor (\n), NoYear (\y) and NoTitle (\t) flags. I know that in '(Darwin, 1859)' I could suppress the author to get to '(1859)' and then manually type 'Darwin ' in front of it. I'm just wondering if, through some unknown flag, it is possible to indicate that it should be 'Darwin (1859)' from the start so that the end user doesn't have to type 'Darwin' at all.

  • Yves:

    You are right that you can use string-length or text to verify if the element exists. String-length is actually used in the built-in styles to check if elements exist; however, the count will also work as the tags are deleted when the string-length is zero. Unfortunately, there is no such flag that does what you want.

  • Nathan, My problem is:

    Here in Brazil when we have more than 2 authors we write the first one and "et.al".

    I how that office can see that I have different authors if I input them with ";" between. So my point is:

    Is there a counter that I can use?

    How can I create a counter and input values for it? Thanks Julio Cesar Silva

  • Julio, Each author is stored as a b:Person element inside a b:NameList element. You can use the count function to count the number of authors. and et al. Anonymous work.

  • I prepare a simple sheet with this blog help, but it is not working. I had one sheet with book reference ok, but without et al. in case of multiples authors, so I tried to include this counter withou sucess :(

    Could you help me? 2006.5.07 COPPE b:Author/b:Author/b:NameList b:Title b:Year b:Edition b:City b:Publisher , , , , , , , , et al. Anonymous work. , . , , , ( , ) Thank you for help Julio Cesar

  • Hi all, Having better ideas...

    I think that the short way to make this work for ABNT Brasil, is begin with a style, like chicago (just have et al.), and make the changes.

    Simple changes... like order of fields and format.

    Example: I need a biliography for Book like this:

    Last Name Author[1], First Name Author[1], Title (Bold or Italic), Edition, City, Publisher, Year. Could we work on this way?

    Say you to me where fomat and order is? or set you it to us? Thank you for help. Julio Cesar Silva

  • Julio: try to contact me privately through the link under my name (yours was empty, so I can't reach you). Also, if you are going to start editing one of the predefined styles, I suggest you use the ones coming with Word 2008 rather than Word 2007 as those contain comments about what some of the variables do and might be easier to manipulate. Yves

  • Hi Yves - 1)What is the definition of the "SameAuthor", "MinAuthor", and "RepeatedAuthor" elements? Word calculates them internally, but without knowing what they represent, it is hard to use them.

    1a. SameAuthor The SameAuthor is used in the bibliographies for the MLA, Chicago, ISO690, and SIST styles. This element is the character used when adjacent bibliography entries have the same author (taking into account multiple authors as well). The second, third, fourth, etc. adjacent entries use the SameAuthor character in place of the author. Smith, John. MyBook0. n.d.

    —. MyBook1. n.d.

    —. MyBook1. n.d.

    Title. Vol. Vol. Pub, n.d. All of the built-in styles define the SameAuthor character as an em-dash (Unicode character U+2014), but it is up to the XSLT to decided how to use this element appropriately. Word defines this on an XSLT-basis only.

    1b. MinAuthors The MinAuthors element is used in citations for the Turabian and Chicago styles, and is used to skip the output of the nth author, where n > MinAuthors. Word does take into account all of the different kinds of “authors” mentioned. The value of MinAuthors is the result of comparing the authors for the current citation with the other authors in the document’s current list of used sources. If we find that an author matches across multiple source entries, then MinAuthors represents the number of author of the source matched. 1c. RepeatedAuthor This element controls what the style (XSLT) should do in the case that the author string is empty. The RepeatedAuthor element is used by Word in the citations for the APA, Chicago, MLA, and Turabian styles, and does take into account all of the different kinds of “authors” mentioned. If the “author” is empty and the RepeatedAuthor element is present, then Word will substitute in the contents of the “title” --- which varies depending on the presence of several other elements, namely, Title, NoTitle, and ShortTitle. The ShortTitle and NoTitle elements will be given priority over the Title element. 2)Do the above elements (question 1) take into account that the 'author' is not always the Author? For example: Interview -> b:Interviewer, Art -> b:Artist, Book -> b:Author. 2. Answered in the response for question 1. 3)Can a character style be directly applied to in-text citations from within the xslt? I mean, bibliographies get the MsoBibliography paragraph style applied to them. Can in-text citations get a similar MsoCitation character style applied to them? If so, what is its name? Right now it seems an in-text citation inherits its 'surrounding' style making it 'hard' to create superscript in-text citations for example. 3. Because the transforms themselves just produce html, yes, if you use the correct style declaration for html, then it should work (so long as the style is defined). To respond to your particular concern about subscript/superscript, I'd imagine you could just put all of the citation inside a span which defines those properties. As an example, you can try saving an html document from Word and comparing how Word saves out subscript/superscript properties to html. 4)Is there a(n undocumented) flag to indicate if an in-text citation should be of a different form? Basically, how can you differentiate between: a)Darwin (1859) wrote that ...

    b)... known as turtles (Darwin, 1859). 4. No such flag exists. - Jonathan (MS)

  • Thanks for the informative answers Jonathan. Regarding point 3. While both and elements are formatted correctly as superscript in a bibliography, they are NOT in an in-text citation. (If you want an example style, I can provide one) Testing has shown me that only simple formatting such as or is processed as expected for in-text citations. Unlike bibliographies, it looks like it is not possible to use a predefined style definition for in-text citations either. They are just stripped away and the style used by the surrounding text is used instead. Yves

  • Hi Jonathan, thanks, this post was very helpfull and I started creating custom style used by my university. However in my locale LCID=1063 (Lithuanian, LT) the value of b:Strings/b:PageShort and b:Strings/b:PagesCountinousShort should be "p." instead of "psl." I made a workaround for it, but I would love to see it fixed. I was unable to find any usefull information how to file a bug. BTW, this is official short version for pages. It is regulated by The State Commission of the Lithuanian Language: www.vlkk.lt/.../sutrumpinimai.html

    From their website: "p. -- ponas, -ia, panelė; puslapis; punktas", where "puslapis" means page (same short version "p." is used for plural). - Domas

  • Hello Nathan Kwan,

    Your lovely programming is very helful. Thank you for that!

    Unfurtunatly, I am writing my essay in Hebrew (which is being written from Right to Left), so I find dificullty formatting the brackets and adjust it to the Right toLeft writing direction, especially when the citation continues to the second line.

    Do you have any solution for me?  

    Thank you

1 2  Next >
Comments

Comments: (loading) Collapse