Repository: NREL/OpenStudio (language: python)

Issue:
Use XMLValidator to validate the measure.xml
Enhancement Request
--------------

Now that we have all the buildings blocks needed, it's probably a good idea to add this feature.

## Detailed Description

This will require fixing the way we write datetimes to the measure.xml.

```
[openstudio.XMLValidator] <1> xsdValidate.parseFileError: XML error 17.1824: Element 'version_modified': '20170316T161836Z' is not a valid value of the atomic type 'xs:dateTime'.
    at /media/DataExt4/Software/Others/OpenStudio/resources/utilities/BCL/./Measures/v3/IncreaseRoofRValue/measure.xml:6 while processing "20170316T161836Z"
```

## Possible Implementation

Quite simple, embed the measure schema, use XMLValidator. Similar to what we do for gbXML already

Make sorting of files in measure.xml consistent
Issue overview
--------------
When you run `openstudio.exe measure --update ./` on a measure to update the `measure.xml` file, sometimes the order of the files in the `<files>` element changes. Not sure if this is a result of running on Windows vs. Mac, but it's annoying when reviewing diffs to make sure that only the expected resource files in the measure changed. See the image below, which shows a diff. The checksums for some of the files changed, but for some reason the files order in the xml also changed, making the diff hard to review.

![image](https://user-images.githubusercontent.com/2009290/204385919-69d85d47-227b-45a9-9e61-43b65186e7de.png)


## Current Behavior
When you run `openstudio.exe measure --update ./` on a measure to update the `measure.xml` file, sometimes the order of the files in the `<files>` element changes. Don't know if this is a cross-platform issue, related to how the files are located and sorted, or what.

## Expected Behavior
No matter which platform you run the command on, or how many times you run it, the order of the files listed in the `<files>` element should change. If the contents of those files did change, the diff in the file should just show changes on the `<checksum>` lines for those files.

## Steps to Reproduce
1. Get a measure with resource files
2. Change something in one of the resource files or in the README.md or the README.md.erb or the test
3. Run `openstudio measure --update ./` on all platforms. Review a diff of the measure.xml file.

### Environment

Some additional details about your environment for this issue (if relevant):
 - Platform: Windows 10
 - Version of OpenStudio: OpenStudio 3.4.0

### Context
The current behavior makes diffs of the measure.xml files for ComStock difficult to review.

Make sorting of files in measure.xml consistent
Issue overview
--------------
When you run `openstudio.exe measure --update ./` on a measure to update the `measure.xml` file, sometimes the order of the files in the `<files>` element changes. Not sure if this is a result of running on Windows vs. Mac, but it's annoying when reviewing diffs to make sure that only the expected resource files in the measure changed. See the image below, which shows a diff. The checksums for some of the files changed, but for some reason the files order in the xml also changed, making the diff hard to review.

![image](https://user-images.githubusercontent.com/2009290/204385919-69d85d47-227b-45a9-9e61-43b65186e7de.png)


## Current Behavior
When you run `openstudio.exe measure --update ./` on a measure to update the `measure.xml` file, sometimes the order of the files in the `<files>` element changes. Don't know if this is a cross-platform issue, related to how the files are located and sorted, or what.

## Expected Behavior
No matter which platform you run the command on, or how many times you run it, the order of the files listed in the `<files>` element should change. If the contents of those files did change, the diff in the file should just show changes on the `<checksum>` lines for those files.

## Steps to Reproduce
1. Get a measure with resource files
2. Change something in one of the resource files or in the README.md or the README.md.erb or the test
3. Run `openstudio measure --update ./` on all platforms. Review a diff of the measure.xml file.

### Environment

Some additional details about your environment for this issue (if relevant):
 - Platform: Windows 10
 - Version of OpenStudio: OpenStudio 3.4.0

### Context
The current behavior makes diffs of the measure.xml files for ComStock difficult to review.

Make sorting of files in measure.xml consistent
Issue overview
--------------
When you run `openstudio.exe measure --update ./` on a measure to update the `measure.xml` file, sometimes the order of the files in the `<files>` element changes. Not sure if this is a result of running on Windows vs. Mac, but it's annoying when reviewing diffs to make sure that only the expected resource files in the measure changed. See the image below, which shows a diff. The checksums for some of the files changed, but for some reason the files order in the xml also changed, making the diff hard to review.

![image](https://user-images.githubusercontent.com/2009290/204385919-69d85d47-227b-45a9-9e61-43b65186e7de.png)


## Current Behavior
When you run `openstudio.exe measure --update ./` on a measure to update the `measure.xml` file, sometimes the order of the files in the `<files>` element changes. Don't know if this is a cross-platform issue, related to how the files are located and sorted, or what.

## Expected Behavior
No matter which platform you run the command on, or how many times you run it, the order of the files listed in the `<files>` element should change. If the contents of those files did change, the diff in the file should just show changes on the `<checksum>` lines for those files.

## Steps to Reproduce
1. Get a measure with resource files
2. Change something in one of the resource files or in the README.md or the README.md.erb or the test
3. Run `openstudio measure --update ./` on all platforms. Review a diff of the measure.xml file.

### Environment

Some additional details about your environment for this issue (if relevant):
 - Platform: Windows 10
 - Version of OpenStudio: OpenStudio 3.4.0

### Context
The current behavior makes diffs of the measure.xml files for ComStock difficult to review.



Discussion / hints:

Has anyone noticed whether it's actually cross-platform issue?  Or has someone seen this happening using the same SDK version?

It's also possible (I would say likely) that it's an OS SDK version issue... we've made a few changes over time as to how we scan for files, and we also updated boost (and it's filesystem library) a few times, so it's possible the change comes from here (and in which case there's nothing to we can do about it...).
A likely culprit at 3.3.0 was this PR: https://github.com/NREL/OpenStudio/pull/4417
I don't know if it's definitely cross platform or an SDK version change, but checking the SDK version should be straightforward.
Has anyone noticed whether it's actually cross-platform issue?  Or has someone seen this happening using the same SDK version?

It's also possible (I would say likely) that it's an OS SDK version issue... we've made a few changes over time as to how we scan for files, and we also updated boost (and it's filesystem library) a few times, so it's possible the change comes from here (and in which case there's nothing to we can do about it...).
A likely culprit at 3.3.0 was this PR: https://github.com/NREL/OpenStudio/pull/4417
I don't know if it's definitely cross platform or an SDK version change, but checking the SDK version should be straightforward.
Has anyone noticed whether it's actually cross-platform issue?  Or has someone seen this happening using the same SDK version?

It's also possible (I would say likely) that it's an OS SDK version issue... we've made a few changes over time as to how we scan for files, and we also updated boost (and it's filesystem library) a few times, so it's possible the change comes from here (and in which case there's nothing to we can do about it...).
A likely culprit at 3.3.0 was this PR: https://github.com/NREL/OpenStudio/pull/4417
I don't know if it's definitely cross platform or an SDK version change, but checking the SDK version should be straightforward.

Fix patch:
diff --git a/ConanInstall.cmake b/ConanInstall.cmake
index 817766b20f2..b2dfdf16a94 100644
--- a/ConanInstall.cmake
+++ b/ConanInstall.cmake
@@ -177,7 +177,7 @@ if(NOT CONAN_OPENSTUDIO_ALREADY_RUN)
     "cpprestsdk/2.10.18#df2f6ac88e47cadd9c9e8e0971e00d89"
     "websocketpp/0.8.2#3fd704c4c5388d9c08b11af86f79f616"
     "geographiclib/1.52#76536a9315a003ef3511919310b2fe37"
-    "swig/4.0.2#9fcccb1e39eed9acd53a4363d8129be5"
+    "swig/4.1.0#f4419c5ab88f877272cbaa36dd0237ff"
     "tinygltf/2.5.0#c8b2aca9505e86312bb42aa0e1c639ec"
     "cli11/2.3.2#8ccdf14fb1ad53532d498c16ae580b4b"
     ${CONAN_GTEST}
diff --git a/src/utilities/CMakeLists.txt b/src/utilities/CMakeLists.txt
index 366d51f4b05..863ac833fc2 100644
--- a/src/utilities/CMakeLists.txt
+++ b/src/utilities/CMakeLists.txt
@@ -188,6 +188,7 @@ set(bcl_src
   bcl/BCL.cpp
   bcl/BCLComponent.hpp
   bcl/BCLComponent.cpp
+  bcl/BCLEnums.hpp
   bcl/BCLFileReference.hpp
   bcl/BCLFileReference.cpp
   bcl/BCLMeasure.hpp
@@ -504,6 +505,7 @@ add_library(openstudio_utilities_minimal
   core/StringStreamLogSink.hpp
   core/StringStreamLogSink_Impl.hpp
   core/StringStreamLogSink.cpp
+  bcl/BCLEnums.hpp
 )
 target_link_libraries(openstudio_utilities_minimal PUBLIC ${${target_name}_depends})
 
@@ -572,6 +574,6 @@ MAKE_SWIG_TARGET(OpenStudioUtilitiesSql utilitiessql "${CMAKE_CURRENT_SOURCE_DIR
 MAKE_SWIG_TARGET(OpenStudioUtilitiesTime utilitiestime "${CMAKE_CURRENT_SOURCE_DIR}/UtilitiesTime.i" "${${target_name}_swig_src}" ${swig_target_name} OpenStudioUtilitiesSql)
 MAKE_SWIG_TARGET(OpenStudioUtilitiesUnits utilitiesunits "${CMAKE_CURRENT_SOURCE_DIR}/UtilitiesUnits.i" "${${target_name}_swig_src}" ${swig_target_name} OpenStudioUtilitiesTime)
 MAKE_SWIG_TARGET(OpenStudioUtilitiesFileTypes utilitiesfiletypes "${CMAKE_CURRENT_SOURCE_DIR}/UtilitiesFileTypes.i" "${${target_name}_swig_src}" ${swig_target_name} OpenStudioUtilitiesUnits)
-MAKE_SWIG_TARGET(OpenStudioUtilitiesXML utilitiesxml "${CMAKE_CURRENT_SOURCE_DIR}/UtilitiesXML.i" "${${target_name}_swig_src}" ${swig_target_name} OpenStudioUtilitiesCore)
+MAKE_SWIG_TARGET(OpenStudioUtilitiesXML utilitiesxml "${CMAKE_CURRENT_SOURCE_DIR}/UtilitiesXML.i" "${${target_name}_swig_src}" ${swig_target_name} OpenStudioUtilitiesBCL)
 
 MAKE_SWIG_TARGET(OpenStudioUtilities utilities "${CMAKE_CURRENT_SOURCE_DIR}/Utilities.i" "${${target_name}_swig_src}" ${swig_target_name} OpenStudioUtilitiesFileTypes)
diff --git a/src/utilities/bcl/BCLEnums.hpp b/src/utilities/bcl/BCLEnums.hpp
new file mode 100644
index 00000000000..0b7a45cc847
--- /dev/null
+++ b/src/utilities/bcl/BCLEnums.hpp
@@ -0,0 +1,94 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+*  following conditions are met:
+*
+*  (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+*  disclaimer.
+*
+*  (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+*  disclaimer in the documentation and/or other materials provided with the distribution.
+*
+*  (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products
+*  derived from this software without specific prior written permission from the respective party.
+*
+*  (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works
+*  may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior
+*  written permission from Alliance for Sustainable Energy, LLC.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED
+*  STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+*  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+*  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************************************************************/
+
+#ifndef UTILITIES_BCL_BCLENUMS_HPP
+#define UTILITIES_BCL_BCLENUMS_HPP
+
+#include "../core/Enum.hpp"
+
+namespace openstudio {
+
+// clang-format off
+
+/** \class MeasureType
+ *  \brief Enumeration of the types of BCLMeasure, by input file type.
+ *  \details ModelMeasures accept OpenStudio Models as input; EnergyPlusMeasures accept
+ *  EnergyPlus IDF files as input; and UtilityMeasures do not operate on any sort of energy
+ *  model. See the OPENSTUDIO_ENUM documentation in utilities/core/Enum.hpp. The actual macro
+ *  call is:
+ *  \code
+OPENSTUDIO_ENUM( MeasureType,
+  ((ModelMeasure)(Model Measure))
+  ((EnergyPlusMeasure)(EnergyPlus Measure))
+  ((UtilityMeasure)(Utility Measure))
+  ((ReportingMeasure)(Reporting Measure))
+);
+ *  \endcode */
+OPENSTUDIO_ENUM( MeasureType,
+  ((ModelMeasure)(Model Measure))
+  ((EnergyPlusMeasure)(EnergyPlus Measure))
+  ((UtilityMeasure)(Utility Measure))
+  ((ReportingMeasure)(Reporting Measure))
+);
+
+OPENSTUDIO_ENUM( MeasureBadgeType,
+  ((BCLMeasure))
+  ((MyMeasure))
+  ((OSMeasure))
+);
+
+OPENSTUDIO_ENUM( MeasureLanguage,
+  ((Ruby))
+  ((Python))
+);
+
+/** \class BCLXMLType
+ *  \brief Enumeration of the BCL XML file types.
+ *  \details The Building Component Library (BCL) hosts both components and measures. The
+ *  meta-data for individual instances of these two types of items are transmitted using XML
+ *  files that with slightly different structures. Thus, this enum helps distinguish between the
+ *  expected schema.
+ *
+ *  See the OPENSTUDIO_ENUM documentation in utilities/core/Enum.hpp. The actual macro call is:
+ *  \code
+OPENSTUDIO_ENUM(BCLXMLType,
+  ((ComponentXML)(ComponentXML))
+  ((MeasureXML)(MeasureXML))
+);
+ *  \endcode */
+OPENSTUDIO_ENUM(BCLXMLType,
+  ((ComponentXML)(ComponentXML))
+  ((MeasureXML)(MeasureXML))
+);
+
+// clang-format on
+
+}  // namespace openstudio
+
+#endif  // UTILITIES_BCL_BCLENUMS_HPP
diff --git a/src/utilities/bcl/BCLFileReference.cpp b/src/utilities/bcl/BCLFileReference.cpp
index 9e2e8a9fbdb..5d72084452f 100644
--- a/src/utilities/bcl/BCLFileReference.cpp
+++ b/src/utilities/bcl/BCLFileReference.cpp
@@ -193,6 +193,19 @@ bool BCLFileReference::checkForUpdate() {
   return false;
 }
 
+// bool operator==(const BCLFileReference& lhs, const BCLFileReference& rhs) {
+//   return lhs.m_path == rhs.m_path;
+// }
+//
+// std::strong_ordering operator<=>(const BCLFileReference& lhs, const BCLFileReference& rhs) {
+//   if (lhs.m_path < rhs.m_path) {
+//     return std::strong_ordering::less;
+//   } else if (lhs.m_path == rhs.m_path) {
+//     return std::strong_ordering::equal;
+//   }
+//   return std::strong_ordering::greater;
+// }
+
 std::ostream& operator<<(std::ostream& os, const BCLFileReference& file) {
   pugi::xml_document doc;
   auto element = doc.append_child("File");
diff --git a/src/utilities/bcl/BCLFileReference.hpp b/src/utilities/bcl/BCLFileReference.hpp
index e95ce925db5..a42760e76fd 100644
--- a/src/utilities/bcl/BCLFileReference.hpp
+++ b/src/utilities/bcl/BCLFileReference.hpp
@@ -32,11 +32,8 @@
 
 #include "../core/Logger.hpp"
 #include "../core/Path.hpp"
-#include "../core/Compare.hpp"
 #include "../UtilitiesAPI.hpp"
 
-#include <vector>
-
 namespace pugi {
 class xml_node;
 }
@@ -122,6 +119,20 @@ class UTILITIES_API BCLFileReference
 
   //@}
 
+ protected:
+  // Declaring the equality operator and the spaceship operator (three-way comparison operator) will end up defining all comparison operators
+  // We really need only the operator< for sorting a STL container of BCLFileReference, but might as well be consistent
+  // Comparison is done on m_path. Sorting is useful for BCLXML to avoid reordering of files (see #4748)
+  // TODO: compiler/SWIG support still seems too sparse (need GCC 10+, Apple Clang 13 at least), let's avoid it for now
+  // friend bool operator==(const BCLFileReference& lhs, const BCLFileReference& rhs);
+  // friend std::strong_ordering operator<=>(const BCLFileReference& lhs, const BCLFileReference& rhs);
+  friend inline bool operator==(const BCLFileReference& lhs, const BCLFileReference& rhs) {
+    return lhs.m_path == rhs.m_path;
+  }
+  friend inline bool operator<(const BCLFileReference& lhs, const BCLFileReference& rhs) {
+    return lhs.m_path < rhs.m_path;
+  }
+
  private:
   // configure logging
   REGISTER_LOGGER("utilities.bcl.BCLFileReference");
@@ -141,6 +152,19 @@ class UTILITIES_API BCLFileReference
 /** Prints BCLFileReference to os. \relates BCLFileReference */
 UTILITIES_API std::ostream& operator<<(std::ostream& os, const BCLFileReference& file);
 
+inline bool operator!=(const BCLFileReference& lhs, const BCLFileReference& rhs) {
+  return !operator==(lhs, rhs);
+}
+inline bool operator>(const BCLFileReference& lhs, const BCLFileReference& rhs) {
+  return operator<(rhs, lhs);
+}
+inline bool operator<=(const BCLFileReference& lhs, const BCLFileReference& rhs) {
+  return !operator>(lhs, rhs);
+}
+inline bool operator>=(const BCLFileReference& lhs, const BCLFileReference& rhs) {
+  return !operator<(lhs, rhs);
+}
+
 }  // namespace openstudio
 
 #endif  // UTILITIES_BCL_BCLFILEREFERENCE_HPP
diff --git a/src/utilities/bcl/BCLMeasure.hpp b/src/utilities/bcl/BCLMeasure.hpp
index 50147eb91a6..650b1228326 100644
--- a/src/utilities/bcl/BCLMeasure.hpp
+++ b/src/utilities/bcl/BCLMeasure.hpp
@@ -31,6 +31,7 @@
 #define UTILITIES_BCL_BCLMEASURE_HPP
 
 #include "BCLXML.hpp"
+#include "BCLEnums.hpp"
 #include "../core/Optional.hpp"
 #include "../core/Path.hpp"
 #include "../core/Deprecated.hpp"
@@ -43,42 +44,6 @@ namespace openstudio {
 
 class FileReferenceType;
 
-// clang-format off
-
-/** \class MeasureType
- *  \brief Enumeration of the types of BCLMeasure, by input file type.
- *  \details ModelMeasures accept OpenStudio Models as input; EnergyPlusMeasures accept
- *  EnergyPlus IDF files as input; and UtilityMeasures do not operate on any sort of energy
- *  model. See the OPENSTUDIO_ENUM documentation in utilities/core/Enum.hpp. The actual macro
- *  call is:
- *  \code
-OPENSTUDIO_ENUM( MeasureType,
-  ((ModelMeasure)(Model Measure))
-  ((EnergyPlusMeasure)(EnergyPlus Measure))
-  ((UtilityMeasure)(Utility Measure))
-  ((ReportingMeasure)(Reporting Measure))
-);
- *  \endcode */
-OPENSTUDIO_ENUM( MeasureType,
-  ((ModelMeasure)(Model Measure))
-  ((EnergyPlusMeasure)(EnergyPlus Measure))
-  ((UtilityMeasure)(Utility Measure))
-  ((ReportingMeasure)(Reporting Measure))
-);
-
-OPENSTUDIO_ENUM( MeasureBadgeType,
-  ((BCLMeasure))
-  ((MyMeasure))
-  ((OSMeasure))
-);
-
-OPENSTUDIO_ENUM( MeasureLanguage,
-  ((Ruby))
-  ((Python))
-);
-
-// clang-format on
-
 /** BCLMeasure is a class for managing the contents of a BCL Measure directory including the xml description file.
   **/
 class UTILITIES_API BCLMeasure
diff --git a/src/utilities/bcl/BCLMeasureArgument.cpp b/src/utilities/bcl/BCLMeasureArgument.cpp
index c863ff12229..4ac48d76499 100644
--- a/src/utilities/bcl/BCLMeasureArgument.cpp
+++ b/src/utilities/bcl/BCLMeasureArgument.cpp
@@ -36,17 +36,28 @@
 namespace openstudio {
 
 BCLMeasureArgument::BCLMeasureArgument(const pugi::xml_node& element) {
+
   // TODO: escape name
   // cppcheck-suppress useInitializationList
   m_name = element.child("name").text().as_string();
 
   m_displayName = element.child("display_name").text().as_string();
 
-  m_description = element.child("description").text().as_string();
+  auto getOptionaString = [&element](const char* name) -> boost::optional<std::string> {
+    if (auto subelement = element.child(name)) {
+      const std::string text = subelement.text().as_string();
+      if (!text.empty()) {
+        return {text};
+      }
+    }
+    return boost::none;
+  };
+
+  m_description = getOptionaString("description");
 
   m_type = element.child("type").text().as_string();
 
-  m_units = element.child("units").text().as_string();
+  m_units = getOptionaString("units");
 
   m_required = false;
   std::string test = element.child("required").text().as_string();
@@ -60,12 +71,11 @@ BCLMeasureArgument::BCLMeasureArgument(const pugi::xml_node& element) {
     m_modelDependent = true;
   }
 
-  m_defaultValue = element.child("default_value").text().as_string();
+  m_defaultValue = getOptionaString("default_value");
 
-  auto subelement = element.child("choices");
-  if (subelement) {
+  if (auto subelement = element.child("choices")) {
     for (auto& choiceElement : subelement.children("choice")) {
-      std::string choiceValue = choiceElement.child("value").text().as_string();
+      const std::string choiceValue = choiceElement.child("value").text().as_string();
       if (!choiceValue.empty()) {  // Not exactly the same test as before, probably needs a better test and/or error reporting
         m_choiceValues.push_back(choiceValue);
         auto display_name = choiceElement.child("display_name");
@@ -73,15 +83,14 @@ BCLMeasureArgument::BCLMeasureArgument(const pugi::xml_node& element) {
           // DLM: this is technically an invalid file, attempt to fix it here
           m_choiceDisplayNames.push_back(choiceValue);
         } else {
-          m_choiceDisplayNames.push_back(display_name.text().as_string());
+          m_choiceDisplayNames.emplace_back(display_name.text().as_string());
         }
       }
     }
   }
 
-  m_minValue = element.child("min_value").text().as_string();
-
-  m_maxValue = element.child("max_value").text().as_string();
+  m_minValue = getOptionaString("min_value");
+  m_maxValue = getOptionaString("max_value");
 }
 
 BCLMeasureArgument::BCLMeasureArgument(const std::string& name, const std::string& displayName, const boost::optional<std::string>& description,
@@ -168,7 +177,7 @@ void BCLMeasureArgument::writeValues(pugi::xml_node& element) const {
   if (m_description) {
     subElement = element.append_child("description");
     text = subElement.text();
-    text.set((*m_description).c_str());
+    text.set(m_description->c_str());
   }
 
   subElement = element.append_child("type");
@@ -178,7 +187,7 @@ void BCLMeasureArgument::writeValues(pugi::xml_node& element) const {
   if (m_units) {
     subElement = element.append_child("units");
     text = subElement.text();
-    text.set((*m_units).c_str());
+    text.set(m_units->c_str());
   }
 
   subElement = element.append_child("required");
@@ -192,10 +201,10 @@ void BCLMeasureArgument::writeValues(pugi::xml_node& element) const {
   if (m_defaultValue) {
     subElement = element.append_child("default_value");
     text = subElement.text();
-    text.set((*m_defaultValue).c_str());
+    text.set(m_defaultValue->c_str());
   }
 
-  unsigned n = m_choiceValues.size();
+  const unsigned n = m_choiceValues.size();
   OS_ASSERT(n == m_choiceDisplayNames.size());
   if (n > 0) {
     auto choicesElement = element.append_child("choices");
@@ -215,13 +224,13 @@ void BCLMeasureArgument::writeValues(pugi::xml_node& element) const {
   if (m_minValue) {
     subElement = element.append_child("min_value");
     text = subElement.text();
-    text.set((*m_minValue).c_str());
+    text.set(m_minValue->c_str());
   }
 
   if (m_maxValue) {
     subElement = element.append_child("max_value");
     text = subElement.text();
-    text.set((*m_maxValue).c_str());
+    text.set(m_maxValue->c_str());
   }
 }
 
diff --git a/src/utilities/bcl/BCLXML.cpp b/src/utilities/bcl/BCLXML.cpp
index adfcad59775..42cf1c3c240 100644
--- a/src/utilities/bcl/BCLXML.cpp
+++ b/src/utilities/bcl/BCLXML.cpp
@@ -33,17 +33,24 @@
 #include "../core/Checksum.hpp"
 #include "../core/FilesystemHelpers.hpp"
 #include "../time/DateTime.hpp"
+#include "../xml/XMLValidator.hpp"
 
-#include <sstream>
 #include <pugixml.hpp>
 
+#include <algorithm>
+#include <sstream>
+
 namespace openstudio {
 
+VersionString BCLXML::currentSchemaVersion() {
+  return {3, 1};
+}
+
 BCLXML::BCLXML(const BCLXMLType& bclXMLType)
   : m_bclXMLType(bclXMLType),
     m_uid{removeBraces(openstudio::createUUID())},
     m_versionId{removeBraces(openstudio::createUUID())},
-    m_versionModified{DateTime::nowUTC().toISO8601()} {}
+    m_versionModified{DateTime::nowUTC().toXsdDateTime()} {}
 
 BCLXML::BCLXML(const openstudio::path& xmlPath) : m_path(openstudio::filesystem::system_complete(xmlPath)) {
   if (!openstudio::filesystem::exists(xmlPath)) {
@@ -91,6 +98,12 @@ BCLXML::BCLXML(const openstudio::path& xmlPath) : m_path(openstudio::filesystem:
     }
   }
 
+  // validate the gbxml prior to reverse translation
+  auto bclXMLValidator = XMLValidator::bclXMLValidator(m_bclXMLType, startingVersion);
+  if (!bclXMLValidator.validate(xmlPath)) {
+    LOG(Warn, "Failed to validate measure.xml at " << xmlPath);
+  }
+
   m_name = decodeString(element.child("name").text().as_string());
 
   m_uid = element.child("uid").text().as_string();
@@ -113,7 +126,7 @@ BCLXML::BCLXML(const openstudio::path& xmlPath) : m_path(openstudio::filesystem:
   subelement = element.child("version_modified");
   if (subelement) {
     m_versionModified = subelement.text().as_string();
-    if (!DateTime::fromISO8601(m_versionModified)) {
+    if (!DateTime::fromXsdDateTime(m_versionModified)) {
       // not an allowable date time
       m_versionModified = "";
     }
@@ -338,7 +351,7 @@ std::string BCLXML::versionId() const {
 boost::optional<DateTime> BCLXML::versionModified() const {
   boost::optional<DateTime> result;
   if (!m_versionModified.empty()) {
-    result = DateTime::fromISO8601(m_versionModified);
+    result = DateTime::fromXsdDateTime(m_versionModified);
   }
   return result;
 }
@@ -588,7 +601,8 @@ pugi::xml_document BCLXML::toXML() const {
 
   auto element = docElement.append_child("schema_version");
   auto text = element.text();
-  text.set("3.0");
+  const std::string schemaVersion = BCLXML::currentSchemaVersion().str();
+  text.set(schemaVersion.c_str());
 
   if (m_error) {
     element = docElement.append_child("error");
@@ -727,7 +741,11 @@ pugi::xml_document BCLXML::toXML() const {
 
   // write files
   element = docElement.append_child("files");
-  for (const BCLFileReference& file : m_files) {
+
+  // Fix for #4748 - sort files
+  auto sortedFiles = m_files;
+  std::sort(sortedFiles.begin(), sortedFiles.end());
+  for (const BCLFileReference& file : sortedFiles) {
     auto subelement = element.append_child("file");
     file.writeValues(subelement);
   }
@@ -796,7 +814,7 @@ void BCLXML::changeUID() {
 
 void BCLXML::incrementVersionId() {
   m_versionId = removeBraces(openstudio::createUUID());
-  m_versionModified = DateTime::nowUTC().toISO8601();
+  m_versionModified = DateTime::nowUTC().toXsdDateTime();
 }
 
 bool BCLXML::checkForUpdatesXML() {
diff --git a/src/utilities/bcl/BCLXML.hpp b/src/utilities/bcl/BCLXML.hpp
index ea9283a074c..8bf8d7e6c7d 100644
--- a/src/utilities/bcl/BCLXML.hpp
+++ b/src/utilities/bcl/BCLXML.hpp
@@ -30,6 +30,7 @@
 #ifndef UTILITIES_BCL_BCLXML_HPP
 #define UTILITIES_BCL_BCLXML_HPP
 
+#include "BCLEnums.hpp"
 #include "BCLFileReference.hpp"
 #include "BCLMeasureArgument.hpp"
 #include "BCLMeasureOutput.hpp"
@@ -40,6 +41,7 @@
 #include "../core/Deprecated.hpp"
 #include "../UtilitiesAPI.hpp"
 
+#include <compare>
 #include <vector>
 
 namespace pugi {
@@ -52,29 +54,6 @@ class BCLComponent;
 class BCLMeasure;
 class DateTime;
 
-// clang-format off
-
-/** \class BCLXMLType
- *  \brief Enumeration of the BCL XML file types.
- *  \details The Building Component Library (BCL) hosts both components and measures. The
- *  meta-data for individual instances of these two types of items are transmitted using XML
- *  files that with slightly different structures. Thus, this enum helps distinguish between the
- *  expected schema.
- *
- *  See the OPENSTUDIO_ENUM documentation in utilities/core/Enum.hpp. The actual macro call is:
- *  \code
-OPENSTUDIO_ENUM(BCLXMLType,
-  ((ComponentXML)(ComponentXML))
-  ((MeasureXML)(MeasureXML))
-);
- *  \endcode */
-OPENSTUDIO_ENUM(BCLXMLType,
-  ((ComponentXML)(ComponentXML))
-  ((MeasureXML)(MeasureXML))
-);
-
-// clang-format on
-
 /** BCLXML is a class for accessing the common XML structures of BCLComponent and BCLMeasure.
   **/
 class UTILITIES_API BCLXML
@@ -99,6 +78,9 @@ class UTILITIES_API BCLXML
   /// Decode a string written in xml
   static std::string decodeString(const std::string& txt);
 
+  // Returns the component/measure XSD schema version currently in use when writting a new xml.
+  static VersionString currentSchemaVersion();
+
   //@}
   /** @name Destructor */
   //@{
diff --git a/src/utilities/bcl/LocalBCL.i b/src/utilities/bcl/LocalBCL.i
index 045fc2eb93c..855d637f856 100644
--- a/src/utilities/bcl/LocalBCL.i
+++ b/src/utilities/bcl/LocalBCL.i
@@ -5,6 +5,7 @@
 %import <utilities/core/CommonImport.i>
 
 %{
+  #include <utilities/bcl/BCLEnums.hpp>
   #include <utilities/bcl/BCL.hpp>
   #include <utilities/bcl/BCLComponent.hpp>
   #include <utilities/bcl/BCLFileReference.hpp>
@@ -16,6 +17,21 @@
   #include <utilities/bcl/RemoteBCL.hpp>
   #include <utilities/core/FileReference.hpp>
   #include <utilities/plot/ProgressBar.hpp>
+
+  // TODO: this shouldn't be there really... But I give up refactoring for now
+  #include <utilities/units/Quantity.hpp>
+  #include <utilities/units/Unit.hpp>
+  #include <utilities/units/BTUUnit.hpp>
+  #include <utilities/units/CelsiusUnit.hpp>
+  #include <utilities/units/CFMUnit.hpp>
+  #include <utilities/units/FahrenheitUnit.hpp>
+  #include <utilities/units/GPDUnit.hpp>
+  #include <utilities/units/IPUnit.hpp>
+  #include <utilities/units/Misc1Unit.hpp>
+  #include <utilities/units/MPHUnit.hpp>
+  #include <utilities/units/SIUnit.hpp>
+  #include <utilities/units/ThermUnit.hpp>
+  #include <utilities/units/WhUnit.hpp>
 %}
 
 %ignore componentDownloaded;
@@ -88,6 +104,7 @@
 %template(OptionalMeasureType) boost::optional<openstudio::MeasureType>;
 %template(OptionalMeasureLanguage) boost::optional<openstudio::MeasureLanguage>;
 
+%include <utilities/bcl/BCLEnums.hpp>
 %include <utilities/bcl/BCLFileReference.hpp>
 %include <utilities/bcl/BCLComponent.hpp>
 %include <utilities/bcl/BCLMeasureArgument.hpp>
diff --git a/src/utilities/bcl/RemoteBCL.cpp b/src/utilities/bcl/RemoteBCL.cpp
index b1222f130f4..08c93d05c40 100644
--- a/src/utilities/bcl/RemoteBCL.cpp
+++ b/src/utilities/bcl/RemoteBCL.cpp
@@ -229,13 +229,13 @@ int RemoteBCL::checkForComponentUpdates() {
     m_lastSearch.clear();
 
     auto client = getClient(remoteUrl(), m_timeOutSeconds);
-    web::uri_builder builder(U("/api/search/"));
+    web::uri_builder builder(to_string_t("/api/search/"));
 
-    builder.append_path(U("*.xml"));
+    builder.append_path(to_string_t("*.xml"));
 
-    builder.append_query(U("fq[]"), to_string_t("ss_uuid:" + component.uid()));
+    builder.append_query(to_string_t("fq[]"), to_string_t("ss_uuid:" + component.uid()));
 
-    builder.append_query(U("api_version"), to_string_t(m_apiVersion));
+    builder.append_query(to_string_t("api_version"), to_string_t(m_apiVersion));
 
     // LOG(Debug, m_remoteUrl << builder.to_string());
 
@@ -270,13 +270,13 @@ int RemoteBCL::checkForMeasureUpdates() {
     m_lastSearch.clear();
 
     auto client = getClient(remoteUrl(), m_timeOutSeconds);
-    web::uri_builder builder(U("/api/search/"));
+    web::uri_builder builder(to_string_t("/api/search/"));
 
-    builder.append_path(U("*.xml"));
+    builder.append_path(to_string_t("*.xml"));
 
-    builder.append_query(U("fq[]"), to_string_t("ss_uuid:" + measure.uid()));
+    builder.append_query(to_string_t("fq[]"), to_string_t("ss_uuid:" + measure.uid()));
 
-    builder.append_query(U("api_version"), to_string_t(m_apiVersion));
+    builder.append_query(to_string_t("api_version"), to_string_t(m_apiVersion));
 
     // LOG(Debug, m_remoteUrl << builder.to_string());
 
@@ -491,12 +491,12 @@ bool RemoteBCL::validateAuthKey(const std::string& authKey, const std::string& r
     m_lastSearch.clear();
 
     auto client = getClient(remoteUrl, m_timeOutSeconds);
-    web::uri_builder builder(U("/api/search/"));
+    web::uri_builder builder(to_string_t("/api/search/"));
 
-    builder.append_path(U("*.xml"));
+    builder.append_path(to_string_t("*.xml"));
 
-    builder.append_query(U("api_version"), to_string_t(m_apiVersion));
-    builder.append_query(U("show_rows"), U("0"));
+    builder.append_query(to_string_t("api_version"), to_string_t(m_apiVersion));
+    builder.append_query(to_string_t("show_rows"), to_string_t("0"));
 
     // LOG(Debug, m_remoteUrl << builder.to_string());
 
@@ -601,13 +601,13 @@ bool RemoteBCL::downloadComponent(const std::string& uid) {
   m_downloadUid = uid;
   // request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17");
   auto client = getClient(remoteUrl(), m_timeOutSeconds);
-  web::uri_builder builder(U("/api/component/download"));
+  web::uri_builder builder(to_string_t("/api/component/download"));
 
-  builder.append_query(U("uids"), to_string_t(uid));
+  builder.append_query(to_string_t("uids"), to_string_t(uid));
 
   web::http::http_request msg(web::http::methods::GET);
-  msg.headers().add(U("User-Agent"),
-                    U("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17"));
+  msg.headers().add(to_string_t("User-Agent"),
+                    to_string_t("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17"));
   msg.set_request_uri(builder.to_string());
 
   // LOG(Debug, m_remoteUrl << builder.to_string());
@@ -637,22 +637,22 @@ bool RemoteBCL::startComponentLibraryMetaSearch(const std::string& searchTerm, c
   m_lastMetaSearch.reset();
 
   auto client = getClient(remoteUrl(), m_timeOutSeconds);
-  web::uri_builder builder(U("/api/metasearch/"));
+  web::uri_builder builder(to_string_t("/api/metasearch/"));
 
   // web::uri::encode_data_string will Encodes a string by converting all characters
   // except for RFC 3986 unreserved characters to their hexadecimal representation. (eg: '+' => %2B, ' ' => %20)
   std::string query = searchTerm.empty() ? "*" : searchTerm;
   builder.append_path(web::uri::encode_data_string(utility::conversions::to_string_t(query + ".xml")));
 
-  builder.append_query(U("fq[]"), to_string_t("bundle:" + filterType));
+  builder.append_query(to_string_t("fq[]"), to_string_t("bundle:" + filterType));
 
   if (!componentType.empty() && componentType != "*") {
     std::string filter = (filterType == "nrel_component") ? "sm_vid_Component_Tags" : "sm_vid_Measure_Tags";
     filter += ":\"" + componentType + "\"";
-    builder.append_query(U("fq[]"), to_string_t(filter));
+    builder.append_query(to_string_t("fq[]"), to_string_t(filter));
   }
 
-  builder.append_query(U("api_version"), to_string_t(m_apiVersion));
+  builder.append_query(to_string_t("api_version"), to_string_t(m_apiVersion));
 
   m_httpResponse = client.request(web::http::methods::GET, builder.to_string())
                      .then([](web::http::http_response resp) { return resp.extract_utf8string(); })
@@ -684,19 +684,19 @@ bool RemoteBCL::startComponentLibraryMetaSearch(const std::string& searchTerm, c
   m_lastMetaSearch.reset();
 
   auto client = getClient(remoteUrl(), m_timeOutSeconds);
-  web::uri_builder builder(U("/api/metasearch/"));
+  web::uri_builder builder(to_string_t("/api/metasearch/"));
 
   std::string query = searchTerm.empty() ? "*" : searchTerm;
   builder.append_path(web::uri::encode_data_string(utility::conversions::to_string_t(query + ".xml")));
 
-  builder.append_query(U("fq[]"), to_string_t("bundle:" + filterType));
+  builder.append_query(to_string_t("fq[]"), to_string_t("bundle:" + filterType));
 
   if (componentTypeTID != 0) {
     std::string filter = "tid:" + openstudio::string_conversions::number(componentTypeTID);
-    builder.append_query(U("fq[]"), to_string_t(filter));
+    builder.append_query(to_string_t("fq[]"), to_string_t(filter));
   }
 
-  builder.append_query(U("api_version"), to_string_t(m_apiVersion));
+  builder.append_query(to_string_t("api_version"), to_string_t(m_apiVersion));
 
   m_httpResponse = client.request(web::http::methods::GET, builder.to_string())
                      .then([](web::http::http_response resp) { return resp.extract_utf8string(); })
@@ -729,22 +729,22 @@ bool RemoteBCL::startComponentLibrarySearch(const std::string& searchTerm, const
   m_lastSearch.clear();
 
   auto client = getClient(remoteUrl(), m_timeOutSeconds);
-  web::uri_builder builder(U("/api/search/"));
+  web::uri_builder builder(to_string_t("/api/search/"));
 
   std::string query = searchTerm.empty() ? "*" : searchTerm;
   builder.append_path(web::uri::encode_data_string(utility::conversions::to_string_t(query + ".xml")));
 
-  builder.append_query(U("fq[]"), to_string_t("bundle:" + filterType));
+  builder.append_query(to_string_t("fq[]"), to_string_t("bundle:" + filterType));
 
   if (!componentType.empty() && componentType != "*") {
     std::string filter = (filterType == "nrel_component") ? "sm_vid_Component_Tags" : "sm_vid_Measure_Tags";
     filter += ":\"" + componentType + "\"";
-    builder.append_query(U("fq[]"), to_string_t(filter));
+    builder.append_query(to_string_t("fq[]"), to_string_t(filter));
   }
 
-  builder.append_query(U("api_version"), to_string_t(m_apiVersion));
-  builder.append_query(U("show_rows"), to_string_t(openstudio::string_conversions::number(m_numResultsPerQuery)));
-  builder.append_query(U("page"), to_string_t(openstudio::string_conversions::number(page)));
+  builder.append_query(to_string_t("api_version"), to_string_t(m_apiVersion));
+  builder.append_query(to_string_t("show_rows"), to_string_t(openstudio::string_conversions::number(m_numResultsPerQuery)));
+  builder.append_query(to_string_t("page"), to_string_t(openstudio::string_conversions::number(page)));
 
   m_httpResponse = client.request(web::http::methods::GET, builder.to_string())
                      .then([](web::http::http_response resp) { return resp.extract_utf8string(); })
@@ -771,20 +771,20 @@ bool RemoteBCL::startComponentLibrarySearch(const std::string& searchTerm, const
   m_lastSearch.clear();
 
   auto client = getClient(remoteUrl(), m_timeOutSeconds);
-  web::uri_builder builder(U("/api/search/"));
+  web::uri_builder builder(to_string_t("/api/search/"));
 
   std::string query = searchTerm.empty() ? "*" : searchTerm;
   builder.append_path(web::uri::encode_data_string(utility::conversions::to_string_t(query + ".xml")));
 
-  builder.append_query(U("fq[]"), to_string_t("bundle:" + filterType));
+  builder.append_query(to_string_t("fq[]"), to_string_t("bundle:" + filterType));
 
   if (componentTypeTID != 0) {
     std::string filter = "tid:" + openstudio::string_conversions::number(componentTypeTID);
-    builder.append_query(U("fq[]"), to_string_t(filter));
+    builder.append_query(to_string_t("fq[]"), to_string_t(filter));
   }
-  builder.append_query(U("api_version"), to_string_t(m_apiVersion));
-  builder.append_query(U("show_rows"), to_string_t(openstudio::string_conversions::number(m_numResultsPerQuery)));
-  builder.append_query(U("page"), to_string_t(openstudio::string_conversions::number(page)));
+  builder.append_query(to_string_t("api_version"), to_string_t(m_apiVersion));
+  builder.append_query(to_string_t("show_rows"), to_string_t(openstudio::string_conversions::number(m_numResultsPerQuery)));
+  builder.append_query(to_string_t("page"), to_string_t(openstudio::string_conversions::number(page)));
 
   m_httpResponse = client.request(web::http::methods::GET, builder.to_string())
                      .then([](web::http::http_response resp) { return resp.extract_utf8string(); })
diff --git a/src/utilities/bcl/RemoteBCL.hpp b/src/utilities/bcl/RemoteBCL.hpp
index 8079d346f3e..c4ae3566500 100644
--- a/src/utilities/bcl/RemoteBCL.hpp
+++ b/src/utilities/bcl/RemoteBCL.hpp
@@ -38,6 +38,8 @@
 #  pragma GCC diagnostic push
 #  pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
 #endif
+// Macro U from cpprestsdk is clashing with (cf boost https://github.com/microsoft/cpprestsdk/issues/1214)
+#define _TURN_OFF_PLATFORM_STRING
 #include <cpprest/http_client.h>
 #if (defined(__GNUC__))
 #  pragma GCC diagnostic pop
diff --git a/src/utilities/time/DateTime.cpp b/src/utilities/time/DateTime.cpp
index 5a2eb3b7c8c..2b2ea151adb 100644
--- a/src/utilities/time/DateTime.cpp
+++ b/src/utilities/time/DateTime.cpp
@@ -184,17 +184,19 @@ double DateTime::utcOffset() const {
 
 /// convert to string
 std::string DateTime::toString() const {
-  boost::posix_time::ptime pt(m_date.impl(), m_time.impl() - boost::posix_time::time_duration(utcOffsetHours(), utcOffsetMinutes(), 0, 0));
+  const boost::posix_time::ptime pt(m_date.impl(), m_time.impl() - boost::posix_time::time_duration(utcOffsetHours(), utcOffsetMinutes(), 0, 0));
   return boost::posix_time::to_simple_string(pt);
 }
 
 std::string DateTime::toISO8601() const {
-  boost::posix_time::ptime pt(m_date.impl(), m_time.impl());
+  // 20160713T160843-06:00
+  // 20160713T160843Z
+  const boost::posix_time::ptime pt(m_date.impl(), m_time.impl());
   std::string result = boost::posix_time::to_iso_string(pt);
   if (m_utcOffset == 0.0) {
     result += "Z";
   } else {
-    Time temp(0, utcOffsetHours(), utcOffsetMinutes(), 0);
+    const Time temp(0, utcOffsetHours(), utcOffsetMinutes(), 0);
     char offset = '+';
     if (temp.totalHours() < 0) {
       offset = '-';
@@ -207,14 +209,22 @@ std::string DateTime::toISO8601() const {
 
 std::string DateTime::toXsdDateTime() const {
   // 2016-07-13T16:08:43-06:00
-  Time temp(0, utcOffsetHours(), utcOffsetMinutes(), 0);
-  char offset = '+';
-  if (temp.totalHours() < 0) {
-    offset = '-';
+  // 2016-07-13T16:08:43Z
+
+  const boost::posix_time::ptime pt(m_date.impl(), m_time.impl());
+  std::string result = boost::posix_time::to_iso_extended_string(pt);
+  if (m_utcOffset == 0.0) {
+    result += "Z";
+  } else {
+    const Time temp(0, utcOffsetHours(), utcOffsetMinutes(), 0);
+    char offset = '+';
+    if (temp.totalHours() < 0) {
+      offset = '-';
+    }
+    result += fmt::format("{}{:02d}:{:02d}", offset, std::abs(temp.hours()), std::abs(temp.minutes()));
   }
 
-  return fmt::format("{:04d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}{}{:02d}:{:02d}", 2005, 2, 27, m_time.hours(), m_time.minutes(), m_time.seconds(),
-                     offset, std::abs(temp.hours()), std::abs(temp.minutes()));
+  return result;
 }
 
 std::time_t DateTime::toEpoch() const {
diff --git a/src/utilities/time/Test/DateTime_GTest.cpp b/src/utilities/time/Test/DateTime_GTest.cpp
index 298c0e230d6..ed597f50507 100644
--- a/src/utilities/time/Test/DateTime_GTest.cpp
+++ b/src/utilities/time/Test/DateTime_GTest.cpp
@@ -217,6 +217,9 @@ TEST(DateTime, ISO8601Conversions_2) {
   EXPECT_EQ(0, test->time().seconds());
   EXPECT_EQ(1, test->utcOffset());
 
+  EXPECT_EQ("19970716T192000+0100", test->toISO8601());
+  EXPECT_EQ("1997-07-16T19:20:00+01:00", test->toXsdDateTime());
+
   test = DateTime::fromISO8601("19970716T1920+0100");
   ASSERT_TRUE(test);
   EXPECT_EQ(1997, test->date().year());
@@ -237,6 +240,9 @@ TEST(DateTime, ISO8601Conversions_2) {
   EXPECT_EQ(0, test->time().seconds());
   EXPECT_EQ(0, test->utcOffset());
 
+  EXPECT_EQ("19970716T192000Z", test->toISO8601());
+  EXPECT_EQ("1997-07-16T19:20:00Z", test->toXsdDateTime());
+
   test = DateTime::fromISO8601("19970716T1920");
   ASSERT_TRUE(test);
   EXPECT_EQ(1997, test->date().year());
diff --git a/src/utilities/xml/XMLValidator.cpp b/src/utilities/xml/XMLValidator.cpp
index 990b4d5b0bb..76b38cd2c78 100644
--- a/src/utilities/xml/XMLValidator.cpp
+++ b/src/utilities/xml/XMLValidator.cpp
@@ -32,8 +32,9 @@
 #include "XMLUtils.hpp"
 #include "XMLInitializer.hpp"
 
-#include "utilities/core/Filesystem.hpp"
-#include "utilities/core/FilesystemHelpers.hpp"
+#include "../core/Filesystem.hpp"
+#include "../core/FilesystemHelpers.hpp"
+#include "../bcl/BCLEnums.hpp"
 
 #include <libxml/xmlversion.h>
 #include <libxml/xmlreader.h>
@@ -499,9 +500,41 @@ XMLValidator XMLValidator::gbxmlValidator() {
   if (tmpDir.empty()) {
     LOG_AND_THROW("Failed to create a temporary directory for extracting the embedded path");
   }
-  bool quiet = true;
+  const bool quiet = true;
   ::openstudio::embedded_files::extractFile(":/xml/resources/GreenBuildingXML_Ver6.01.xsd", openstudio::toString(tmpDir), quiet);
   return XMLValidator(tmpDir / "GreenBuildingXML_Ver6.01.xsd");
 }
 
+XMLValidator XMLValidator::bclXMLValidator(openstudio::BCLXMLType bclXMLType, const VersionString& schemaVersion) {
+
+  const auto tmpDir = openstudio::filesystem::create_temporary_directory("xmlvalidation");
+  if (tmpDir.empty()) {
+    LOG_AND_THROW("Failed to create a temporary directory for extracting the embedded path");
+  }
+
+  int schemaVersionMajor = schemaVersion.major();
+  int schemaVersionMinor = schemaVersion.minor();
+
+  if (schemaVersionMajor < 2 || schemaVersionMajor > 3) {
+    LOG_AND_THROW("Unknown schema major version " << schemaVersionMajor << ", accepted = [2, 3]");
+  }
+  if ((schemaVersionMinor != 0) && !((schemaVersionMajor == 3) && (schemaVersionMinor == 1))) {
+    LOG_AND_THROW("Unknown schema version combination " << schemaVersionMajor << "." << schemaVersionMinor << ", accepted = [2.0, 3.0, 3.1]");
+  }
+
+  std::string schemaName;
+  if (bclXMLType == BCLXMLType::ComponentXML) {
+    schemaName = "component";
+  } else if (bclXMLType == BCLXMLType::MeasureXML) {
+    schemaName = "measure";
+  } else {
+    LOG_AND_THROW("Unknown BCLXMLType " << bclXMLType.valueName());
+  }
+  schemaName = fmt::format("{}_v{}.{}.xsd", schemaName, schemaVersionMajor, schemaVersionMinor);
+
+  const bool quiet = true;
+  ::openstudio::embedded_files::extractFile(fmt::format(":/xml/resources/bcl/{}", schemaName), openstudio::toString(tmpDir), quiet);
+  return XMLValidator(tmpDir / schemaName);
+}
+
 }  // namespace openstudio
diff --git a/src/utilities/xml/XMLValidator.hpp b/src/utilities/xml/XMLValidator.hpp
index 959aafe2449..c70b823001f 100644
--- a/src/utilities/xml/XMLValidator.hpp
+++ b/src/utilities/xml/XMLValidator.hpp
@@ -32,11 +32,13 @@
 
 #include "../UtilitiesAPI.hpp"
 
-#include "../core/Path.hpp"
+#include "../core/Compare.hpp"
 #include "../core/Logger.hpp"
 #include "../core/LogMessage.hpp"
 #include "../core/Optional.hpp"
+#include "../core/Path.hpp"
 #include "../core/StringStreamLogSink.hpp"
+#include "../bcl/BCLEnums.hpp"
 
 #include <boost/optional.hpp>
 
@@ -76,6 +78,9 @@ class UTILITIES_API XMLValidator
 
   static XMLValidator gbxmlValidator();
 
+  static XMLValidator bclXMLValidator(openstudio::BCLXMLType bclXMLType = openstudio::BCLXMLType::MeasureXML,
+                                      const VersionString& schemaVersion = VersionString(3, 1));
+
   //@}
   /** @name Getters */
   //@{
diff --git a/src/utilities/xml/resources/bcl/component_v2.0.xsd b/src/utilities/xml/resources/bcl/component_v2.0.xsd
new file mode 100644
index 00000000000..aa456cbc894
--- /dev/null
+++ b/src/utilities/xml/resources/bcl/component_v2.0.xsd
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSpy v2011 sp1 (x64) (http://www.altova.com) by Nicholas Long (National Renewable Energy Laboratory) -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:annotation>
+		<xs:documentation>Component.xsd describes the components that are in the building component library or NREL analysis platform library.</xs:documentation>
+	</xs:annotation>
+	<xs:annotation>
+		<xs:documentation>Version - 0.9</xs:documentation>
+	</xs:annotation>
+	<xs:annotation>
+		<xs:documentation>Version - 0.91 - Updated the cost to be more generic</xs:documentation>
+	</xs:annotation>
+	<xs:annotation>
+		<xs:documentation>Version - 0.92 - Added MasterSpec to the elements</xs:documentation>
+	</xs:annotation>
+	<xs:annotation>
+		<xs:documentation>Version - 0.93 - Fixed indentifier typo.  Added datatype element to attributes.  Removed "level_" from fidelity level values.  Removed component_update_id and replaced component_version_id with version_id.</xs:documentation>
+	</xs:annotation>
+	<xs:annotation>
+		<xs:documentation>Version - 0.94 - Made datatype required on attributes and limited the possible options to int, float, and string.  (Solr will break if these are not specified or are specified incorrectly).</xs:documentation>
+	</xs:annotation>
+	<xs:annotation>
+		<xs:documentation>Version - 0.95 - Removed sourceType and versionType extensions because it was creating problems on the site.</xs:documentation>
+	</xs:annotation>
+	<xs:annotation>
+		<xs:documentation>Version - 0.96 - Added start and end times for component costs</xs:documentation>
+	</xs:annotation>
+	<xs:element name="component">
+		<xs:annotation>
+			<xs:documentation>root element defining a component</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="name">
+					<xs:annotation>
+						<xs:documentation>name of the component as to be displayed</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="uid"/>
+				<xs:element name="version_id">
+					<xs:annotation>
+						<xs:documentation>this is used to signal that a new component is available and should replace previously downloaded components</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="masterguide_csi_values" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>values from the MASTERSPEC</xs:documentation>
+					</xs:annotation>
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="masterguide_csi_value" maxOccurs="unbounded"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="description" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>free-form description of the component, will be used for search</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="comment" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>place holder for any comment</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="fidelity_level">
+					<xs:annotation>
+						<xs:documentation>component's level of data abstraction (example:  1-minute data vs. 1-hour data) </xs:documentation>
+					</xs:annotation>
+					<xs:simpleType>
+						<xs:restriction base="xs:string">
+							<xs:enumeration value="1"/>
+							<xs:enumeration value="2"/>
+							<xs:enumeration value="3"/>
+							<xs:enumeration value="4"/>
+							<xs:enumeration value="5"/>
+						</xs:restriction>
+					</xs:simpleType>
+				</xs:element>
+				<xs:element name="provenances">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="provenance" maxOccurs="unbounded">
+								<xs:annotation>
+									<xs:documentation>provenance is used to enter author information.  The comment field can be used to enter information such as project name.</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="author" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>author who uploaded the data, which will be equal to the user account on the bcl site</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="datetime">
+											<xs:annotation>
+												<xs:documentation>date component was uploaded</xs:documentation>
+											</xs:annotation>
+											<xs:simpleType>
+												<xs:restriction base="xs:string">
+													<xs:pattern value="[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+													<xs:pattern value="[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+												</xs:restriction>
+											</xs:simpleType>
+										</xs:element>
+										<xs:element name="comment" minOccurs="0"/>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="tags">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="tag" maxOccurs="unbounded">
+								<xs:annotation>
+									<xs:documentation>tag is used to classify the component</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="attributes">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="attribute" minOccurs="0" maxOccurs="unbounded">
+								<xs:annotation>
+									<xs:documentation>attribute is a descriptor of the component (includes data quality)</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="name"/>
+										<xs:element name="value" type="xs:string"/>
+										<xs:element name="datatype">
+											<xs:simpleType>
+												<xs:restriction base="xs:string">
+													<xs:enumeration value="int"/>
+													<xs:enumeration value="float"/>
+													<xs:enumeration value="string"/>
+												</xs:restriction>
+											</xs:simpleType>
+										</xs:element>
+										<xs:element name="units" minOccurs="0"/>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="source">
+					<xs:annotation>
+						<xs:documentation>source of the data (the origin of the component information)</xs:documentation>
+					</xs:annotation>
+					<xs:complexType>
+						<xs:sequence minOccurs="0">
+							<xs:element name="manufacturer" minOccurs="0"/>
+							<xs:element name="model" minOccurs="0"/>
+							<xs:element name="serial_no" minOccurs="0"/>
+							<xs:element name="year" minOccurs="0"/>
+							<xs:element name="url" minOccurs="0"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="files">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="file" minOccurs="0" maxOccurs="unbounded">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="version">
+											<xs:annotation>
+												<xs:documentation>version of files attached to component</xs:documentation>
+											</xs:annotation>
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="software_program"/>
+													<xs:element name="identifier"/>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="filename" type="xs:string"/>
+										<xs:element name="filetype" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>ies, idf, </xs:documentation>
+											</xs:annotation>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="costs">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="cost" minOccurs="0" maxOccurs="unbounded">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="instance_name" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>name of cost for reference</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="cost_type">
+											<xs:annotation>
+												<xs:documentation>type of cost, includes low, high, average, estimate, etc</xs:documentation>
+											</xs:annotation>
+											<xs:simpleType>
+												<xs:restriction base="xs:string">
+													<xs:enumeration value="low"/>
+													<xs:enumeration value="high"/>
+													<xs:enumeration value="average"/>
+													<xs:enumeration value="estimate"/>
+												</xs:restriction>
+											</xs:simpleType>
+										</xs:element>
+										<xs:element name="category">
+											<xs:annotation>
+												<xs:documentation>ex:  operations and maintenance cost, salvage cost, materials cost, installation cost, upgrade cost, etc.</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="value" type="xs:float">
+											<xs:annotation>
+												<xs:documentation>cost value based on the supplemntal fields</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="units" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>cost unit. If blank, absolute cost is assumed. ex:  $/ft2, $/person, etc.</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="interval" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>number describing the interval on which this cost is incurred.  ex:  1, 6, 12.  Use 0 for onetime costs</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="interval_units" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>interval units. ex:  day, month, year, etc.</xs:documentation>
+											</xs:annotation>
+											<xs:simpleType>
+												<xs:restriction base="xs:string">
+													<xs:enumeration value="year(s)"/>
+													<xs:enumeration value="month(s)"/>
+													<xs:enumeration value="day(s)"/>
+												</xs:restriction>
+											</xs:simpleType>
+										</xs:element>
+										<xs:element name="year" type="xs:int" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>source year of the costs</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="start_year" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>define when this cost will start to incur. Useful when you may not want maintenance costs to start until n years after construction</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="end_year" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>define whne this cost will stop incurring.</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="location" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>the geographic location where the component was costed (i.e. national, colorado, denver, etc).  By default all values should be national averages.</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="currency" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>the currency of the cost.  If blank, USD is assumed.</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="source" type="xs:string" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>origin from which the cost data came</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="reference_component_name" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>display name of reference component prior to retrofit (for marginal costs)</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="reference_component_id" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>ID of reference component prior to retrofit (for marginal costs)</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+</xs:schema>
diff --git a/src/utilities/xml/resources/bcl/component_v3.0.xsd b/src/utilities/xml/resources/bcl/component_v3.0.xsd
new file mode 100644
index 00000000000..6dd5e720e0f
--- /dev/null
+++ b/src/utilities/xml/resources/bcl/component_v3.0.xsd
@@ -0,0 +1,457 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSpy v2008 rel. 2 sp2 (http://www.altova.com) by Daniel Macumber (NREL) -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:annotation>
+		<xs:documentation>Component.xsd describes the components that are in the building component library or NREL analysis platform library.</xs:documentation>
+	</xs:annotation>
+	<xs:element name="schema_version" fixed="3.0">
+		<xs:annotation>
+			<xs:documentation>schema version</xs:documentation>
+		</xs:annotation>
+		<xs:simpleType>
+			<xs:restriction base="xs:string"/>
+		</xs:simpleType>
+	</xs:element>
+	<xs:element name="uid" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>universally unique identifier which does not chage</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="version_id" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>identifier which changes each time a new version is created</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="version_modified">
+		<xs:annotation>
+			<xs:documentation>timestamp at which the current version_id was created</xs:documentation>
+		</xs:annotation>
+		<xs:simpleType>
+			<xs:restriction base="xs:string">
+				<xs:pattern value="[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+				<xs:pattern value="[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+			</xs:restriction>
+		</xs:simpleType>
+	</xs:element>
+	<xs:element name="xml_checksum" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>checksum of selected xml elements and attributes, used to detect changes to the xml</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="error">
+		<xs:annotation>
+			<xs:documentation>record an error with this component or measure</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>snake cased machine readable name</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="display_name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>user facing name</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="description" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>user facing description</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="modeler_description" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>technical description of implementation details</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="class_name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>for measures only. name of the Ruby class implementing a measure</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="arguments">
+		<xs:annotation>
+			<xs:documentation>for measures only. arguments are computed based on a particular model and passed to the measure at run time.  actual values passed to the measure at run time are not captured here, only properties of the arguments </xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="argument" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element ref="name"/>
+							<xs:element ref="display_name"/>
+							<xs:element ref="description" minOccurs="0"/>
+							<xs:element name="type">
+								<xs:annotation>
+									<xs:documentation>type of the argument</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="Boolean"/>
+										<xs:enumeration value="Double"/>
+										<xs:enumeration value="Integer"/>
+										<xs:enumeration value="String"/>
+										<xs:enumeration value="Choice"/>
+										<xs:enumeration value="Path"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>units of the argument value in format parsable by OpenStudio::convert</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="required" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>true if the argument is required in order for the measure to run</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="model_dependent" type="xs:boolean" default="false">
+								<xs:annotation>
+									<xs:documentation>true if any of this argument's properties depend on the specific model used.  default_value, choice_values, min_value, and max_value will not be populated for dynamic arguments</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="default_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>default value for the argument</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="choices" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>list of allowable values</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="choice" maxOccurs="unbounded">
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="value" type="xs:anySimpleType">
+														<xs:annotation>
+															<xs:documentation>allowable value</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="display_name" type="xs:string">
+														<xs:annotation>
+															<xs:documentation>user facing name for value</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="min_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>minimum value</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="max_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>maximum value</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="masterguide_csi_values">
+		<xs:annotation>
+			<xs:documentation>for components only. values from the MASTERSPEC</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="masterguide_csi_value" maxOccurs="unbounded"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="source">
+		<xs:annotation>
+			<xs:documentation>for components only. source of the data (the origin of the component information)</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence minOccurs="0">
+				<xs:element name="manufacturer" type="xs:string" minOccurs="0"/>
+				<xs:element name="model" minOccurs="0"/>
+				<xs:element name="serial_no" minOccurs="0"/>
+				<xs:element name="year" minOccurs="0"/>
+				<xs:element name="url" minOccurs="0"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="provenances">
+		<xs:annotation>
+			<xs:documentation>provenance is used to enter author information.  </xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="provenance" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="author" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>author who uploaded the content, will be equal to the user account on the bcl site</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="datetime">
+								<xs:annotation>
+									<xs:documentation>date content was uploaded</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:pattern value="[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+										<xs:pattern value="[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="comment" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>general comment</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="tags">
+		<xs:annotation>
+			<xs:documentation>tags are used to classify the content using the appropriate taxonomy.  currently only one tag per piece of content is supported.</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="tag" type="xs:string" maxOccurs="unbounded"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="attributes">
+		<xs:annotation>
+			<xs:documentation>attributes are descriptors of the content.  attributes should be found in the corresponding taxonomy</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="attribute" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="name" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>user facing attribute name (should be found in appropriate taxonomy)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="value" type="xs:anySimpleType"/>
+							<xs:element name="datatype">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="float"/>
+										<xs:enumeration value="integer"/>
+										<xs:enumeration value="string"/>
+										<xs:enumeration value="boolean"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="files">
+		<xs:annotation>
+			<xs:documentation>files lists details on all of the files associated with this piece content</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="file" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="version" minOccurs="0">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="software_program" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>software program the file is associated with</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="identifier" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>version of software program that this file is associated with</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="min_compatible" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>minimum version of the software this file is compatible with, if not specified assumed to be the version identifier</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="max_compatible" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>maximum version of the software this file is compatible with, if not specified assumed to be any version min_compatible or higher</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="filename" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>name of the file</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="filetype" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>ies, idf, </xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="usage_type">
+								<xs:annotation>
+									<xs:documentation>identifies the directory to search for the file in </xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="script"/>
+										<xs:enumeration value="test"/>
+										<xs:enumeration value="resource"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="checksum" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>checksum of the file as computed by OpenStudio::checksum</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="costs">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="cost" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="instance_name" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>name of cost for reference</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="cost_type">
+								<xs:annotation>
+									<xs:documentation>type of cost, includes low, high, average, estimate, etc</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="low"/>
+										<xs:enumeration value="high"/>
+										<xs:enumeration value="average"/>
+										<xs:enumeration value="estimate"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="category">
+								<xs:annotation>
+									<xs:documentation>ex:  operations and maintenance cost, salvage cost, materials cost, installation cost, upgrade cost, etc.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="value" type="xs:float">
+								<xs:annotation>
+									<xs:documentation>cost value based on the supplemntal fields</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="units" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>cost unit. If blank, absolute cost is assumed. ex:  $/ft2, $/person, etc.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="interval" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>number describing the interval on which this cost is incurred.  ex:  1, 6, 12.  Use 0 for onetime costs</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="interval_units" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>interval units. ex:  day, month, year, etc.</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="year(s)"/>
+										<xs:enumeration value="month(s)"/>
+										<xs:enumeration value="day(s)"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="year" type="xs:int" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>source year of the costs</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="start_year" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>define when this cost will start to incur. Useful when you may not want maintenance costs to start until n years after construction</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="end_year" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>define whne this cost will stop incurring.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="location" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>the geographic location where the component was costed (i.e. national, colorado, denver, etc).  By default all values should be national averages.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="currency" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>the currency of the cost.  If blank, USD is assumed.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="source" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>origin from which the cost data came</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="reference_component_name" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>display name of reference component prior to retrofit (for marginal costs)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="reference_component_id" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>ID of reference component prior to retrofit (for marginal costs)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="component">
+		<xs:annotation>
+			<xs:documentation>root element defining a component</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element ref="schema_version"/>
+				<xs:element ref="error" minOccurs="0"/>
+				<xs:element ref="name"/>
+				<xs:element ref="uid"/>
+				<xs:element ref="version_id"/>
+				<xs:element ref="version_modified" minOccurs="0"/>
+				<xs:element ref="xml_checksum"/>
+				<xs:element ref="masterguide_csi_values" minOccurs="0"/>
+				<xs:element ref="display_name"/>
+				<xs:element ref="description"/>
+				<xs:element ref="modeler_description"/>
+				<xs:element ref="provenances"/>
+				<xs:element ref="tags"/>
+				<xs:element ref="attributes"/>
+				<xs:element ref="source"/>
+				<xs:element ref="files"/>
+				<xs:element ref="costs"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+</xs:schema>
diff --git a/src/utilities/xml/resources/bcl/component_v3.1.xsd b/src/utilities/xml/resources/bcl/component_v3.1.xsd
new file mode 100644
index 00000000000..46546c968ff
--- /dev/null
+++ b/src/utilities/xml/resources/bcl/component_v3.1.xsd
@@ -0,0 +1,445 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSpy v2008 rel. 2 sp2 (http://www.altova.com) by Daniel Macumber (NREL) -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:annotation>
+		<xs:documentation>Component.xsd describes the components that are in the building component library or NREL analysis platform library.</xs:documentation>
+	</xs:annotation>
+	<xs:element name="schema_version" fixed="3.1">
+		<xs:annotation>
+			<xs:documentation>schema version</xs:documentation>
+		</xs:annotation>
+		<xs:simpleType>
+			<xs:restriction base="xs:string"/>
+		</xs:simpleType>
+	</xs:element>
+	<xs:element name="uid" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>universally unique identifier which does not chage</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="version_id" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>identifier which changes each time a new version is created</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="version_modified" type="xs:dateTime">
+		<xs:annotation>
+			<xs:documentation>timestamp at which the current version_id was created</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="xml_checksum" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>checksum of selected xml elements and attributes, used to detect changes to the xml</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="error">
+		<xs:annotation>
+			<xs:documentation>record an error with this component or measure</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>snake cased machine readable name</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="display_name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>user facing name</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="description" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>user facing description</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="modeler_description" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>technical description of implementation details</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="class_name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>for measures only. name of the Ruby class implementing a measure</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="arguments">
+		<xs:annotation>
+			<xs:documentation>for measures only. arguments are computed based on a particular model and passed to the measure at run time.  actual values passed to the measure at run time are not captured here, only properties of the arguments </xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="argument" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element ref="name"/>
+							<xs:element ref="display_name"/>
+							<xs:element ref="description" minOccurs="0"/>
+							<xs:element name="type">
+								<xs:annotation>
+									<xs:documentation>type of the argument</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="Boolean"/>
+										<xs:enumeration value="Double"/>
+										<xs:enumeration value="Integer"/>
+										<xs:enumeration value="String"/>
+										<xs:enumeration value="Choice"/>
+										<xs:enumeration value="Path"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>units of the argument value in format parsable by OpenStudio::convert</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="required" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>true if the argument is required in order for the measure to run</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="model_dependent" type="xs:boolean" default="false">
+								<xs:annotation>
+									<xs:documentation>true if any of this argument's properties depend on the specific model used.  default_value, choice_values, min_value, and max_value will not be populated for dynamic arguments</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="default_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>default value for the argument</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="choices" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>list of allowable values</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="choice" maxOccurs="unbounded">
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="value" type="xs:anySimpleType">
+														<xs:annotation>
+															<xs:documentation>allowable value</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="display_name" type="xs:string">
+														<xs:annotation>
+															<xs:documentation>user facing name for value</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="min_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>minimum value</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="max_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>maximum value</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="masterguide_csi_values">
+		<xs:annotation>
+			<xs:documentation>for components only. values from the MASTERSPEC</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="masterguide_csi_value" maxOccurs="unbounded"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="source">
+		<xs:annotation>
+			<xs:documentation>for components only. source of the data (the origin of the component information)</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence minOccurs="0">
+				<xs:element name="manufacturer" type="xs:string" minOccurs="0"/>
+				<xs:element name="model" minOccurs="0"/>
+				<xs:element name="serial_no" minOccurs="0"/>
+				<xs:element name="year" minOccurs="0"/>
+				<xs:element name="url" minOccurs="0"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="provenances">
+		<xs:annotation>
+			<xs:documentation>provenance is used to enter author information.  </xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="provenance" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="author" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>author who uploaded the content, will be equal to the user account on the bcl site</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="datetime" type="xs:dateTime">
+								<xs:annotation>
+									<xs:documentation>date content was uploaded</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="comment" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>general comment</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="tags">
+		<xs:annotation>
+			<xs:documentation>tags are used to classify the content using the appropriate taxonomy.  currently only one tag per piece of content is supported.</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="tag" type="xs:string" maxOccurs="unbounded"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="attributes">
+		<xs:annotation>
+			<xs:documentation>attributes are descriptors of the content.  attributes should be found in the corresponding taxonomy</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="attribute" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="name" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>user facing attribute name (should be found in appropriate taxonomy)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="value" type="xs:anySimpleType"/>
+							<xs:element name="datatype">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="float"/>
+										<xs:enumeration value="integer"/>
+										<xs:enumeration value="string"/>
+										<xs:enumeration value="boolean"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="files">
+		<xs:annotation>
+			<xs:documentation>files lists details on all of the files associated with this piece content</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="file" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="version" minOccurs="0">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="software_program" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>software program the file is associated with</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="identifier" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>version of software program that this file is associated with</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="min_compatible" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>minimum version of the software this file is compatible with, if not specified assumed to be the version identifier</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="max_compatible" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>maximum version of the software this file is compatible with, if not specified assumed to be any version min_compatible or higher</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="filename" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>name of the file</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="filetype" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>ies, idf, </xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="usage_type">
+								<xs:annotation>
+									<xs:documentation>identifies the directory to search for the file in </xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="script"/>
+										<xs:enumeration value="test"/>
+										<xs:enumeration value="resource"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="checksum" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>checksum of the file as computed by OpenStudio::checksum</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="costs">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="cost" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="instance_name" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>name of cost for reference</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="cost_type">
+								<xs:annotation>
+									<xs:documentation>type of cost, includes low, high, average, estimate, etc</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="low"/>
+										<xs:enumeration value="high"/>
+										<xs:enumeration value="average"/>
+										<xs:enumeration value="estimate"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="category">
+								<xs:annotation>
+									<xs:documentation>ex:  operations and maintenance cost, salvage cost, materials cost, installation cost, upgrade cost, etc.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="value" type="xs:float">
+								<xs:annotation>
+									<xs:documentation>cost value based on the supplemntal fields</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="units" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>cost unit. If blank, absolute cost is assumed. ex:  $/ft2, $/person, etc.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="interval" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>number describing the interval on which this cost is incurred.  ex:  1, 6, 12.  Use 0 for onetime costs</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="interval_units" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>interval units. ex:  day, month, year, etc.</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="year(s)"/>
+										<xs:enumeration value="month(s)"/>
+										<xs:enumeration value="day(s)"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="year" type="xs:int" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>source year of the costs</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="start_year" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>define when this cost will start to incur. Useful when you may not want maintenance costs to start until n years after construction</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="end_year" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>define whne this cost will stop incurring.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="location" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>the geographic location where the component was costed (i.e. national, colorado, denver, etc).  By default all values should be national averages.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="currency" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>the currency of the cost.  If blank, USD is assumed.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="source" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>origin from which the cost data came</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="reference_component_name" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>display name of reference component prior to retrofit (for marginal costs)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="reference_component_id" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>ID of reference component prior to retrofit (for marginal costs)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="component">
+		<xs:annotation>
+			<xs:documentation>root element defining a component</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element ref="schema_version"/>
+				<xs:element ref="error" minOccurs="0"/>
+				<xs:element ref="name"/>
+				<xs:element ref="uid"/>
+				<xs:element ref="version_id"/>
+				<xs:element ref="version_modified" minOccurs="0"/>
+				<xs:element ref="xml_checksum"/>
+				<xs:element ref="masterguide_csi_values" minOccurs="0"/>
+				<xs:element ref="display_name"/>
+				<xs:element ref="description"/>
+				<xs:element ref="modeler_description"/>
+				<xs:element ref="provenances"/>
+				<xs:element ref="tags"/>
+				<xs:element ref="attributes"/>
+				<xs:element ref="source"/>
+				<xs:element ref="files"/>
+				<xs:element ref="costs"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+</xs:schema>
diff --git a/src/utilities/xml/resources/bcl/download.sh b/src/utilities/xml/resources/bcl/download.sh
new file mode 100755
index 00000000000..730acb8e6e7
--- /dev/null
+++ b/src/utilities/xml/resources/bcl/download.sh
@@ -0,0 +1,9 @@
+set -x
+
+tag=v0.7.1
+
+curl -sL -o component_v2.0.xsd https://raw.githubusercontent.com/NREL/bcl-gem/$tag/schemas/v2/component_2012_11_08.xsd
+curl -sL -o measure_v2.0.xsd https://raw.githubusercontent.com/NREL/bcl-gem/$tag/schemas/v2/measure_2013_3_26.xsd
+
+curl -sL -o component_v3.0.xsd https://raw.githubusercontent.com/NREL/bcl-gem/$tag/schemas/v3/component_v3.xsd
+curl -sL -o measure_v3.0.xsd https://raw.githubusercontent.com/NREL/bcl-gem/$tag/schemas/v3/measure_v3.xsd
diff --git a/src/utilities/xml/resources/bcl/measure_v2.0.xsd b/src/utilities/xml/resources/bcl/measure_v2.0.xsd
new file mode 100644
index 00000000000..3c15025b1d3
--- /dev/null
+++ b/src/utilities/xml/resources/bcl/measure_v2.0.xsd
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSpy v2010 rel. 3 (http://www.altova.com) by Cynthia McDonald (NREL) -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:annotation>
+		<xs:documentation>Measure.xsd describes the measures that are in the building component library or NREL analysis platform library.</xs:documentation>
+	</xs:annotation>
+	<xs:annotation>
+		<xs:documentation>Version - 0.1</xs:documentation>
+	</xs:annotation>
+	<xs:element name="measure">
+		<xs:annotation>
+			<xs:documentation>root element defining a measure</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="name">
+					<xs:annotation>
+						<xs:documentation>name of the measure</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="uid"/>
+				<xs:element name="version_id">
+					<xs:annotation>
+						<xs:documentation>this is used to signal that a new measure is available and should replace previously downloaded measures</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="description" minOccurs="0">
+					<xs:annotation>
+						<xs:documentation>free-form description of the measure, will be used for search</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="modeler_description">
+					<xs:annotation>
+						<xs:documentation>description containing specific details about the script file</xs:documentation>
+					</xs:annotation>
+				</xs:element>
+				<xs:element name="provenances">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="provenance" minOccurs="0" maxOccurs="unbounded">
+								<xs:annotation>
+									<xs:documentation>provenance is used to enter author information.  The comment field can be used to enter information such as project name.</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="author" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>author who uploaded the data, which will be equal to the user account on the bcl site</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="datetime">
+											<xs:annotation>
+												<xs:documentation>date measure was uploaded</xs:documentation>
+											</xs:annotation>
+											<xs:simpleType>
+												<xs:restriction base="xs:string">
+													<xs:pattern value="[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+													<xs:pattern value="[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+												</xs:restriction>
+											</xs:simpleType>
+										</xs:element>
+										<xs:element name="comment" minOccurs="0"/>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="provenance_required">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="true"/>
+										<xs:enumeration value="false"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="tags">
+					<xs:annotation>
+						<xs:documentation>tags are used to classify the measure (using the measures taxonomy)</xs:documentation>
+					</xs:annotation>
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="tag" maxOccurs="unbounded"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="attributes">
+					<xs:annotation>
+						<xs:documentation>attributes are descriptors of the measure.  Measures will most likely have a measure type attribute (Replacement/Addition/ Removal)</xs:documentation>
+					</xs:annotation>
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="os_version" minOccurs="0"/>
+							<xs:element name="attribute" minOccurs="0" maxOccurs="unbounded">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="name"/>
+										<xs:element name="value" type="xs:string"/>
+										<xs:element name="datatype"/>
+										<xs:element name="units" minOccurs="0"/>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+				<xs:element name="files">
+					<xs:annotation>
+						<xs:documentation>files lists details on all of the files associated with this measure, including arguments for script files.</xs:documentation>
+					</xs:annotation>
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="file" minOccurs="0" maxOccurs="unbounded">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="version">
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="software_program"/>
+													<xs:element name="identifier"/>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+										<xs:element name="filename" type="xs:string"/>
+										<xs:element name="usage_type">
+											<xs:annotation>
+												<xs:documentation>What type of file?  (scripts, resources, tests)</xs:documentation>
+											</xs:annotation>
+											<xs:simpleType>
+												<xs:restriction base="xs:string">
+													<xs:enumeration value="scripts"/>
+													<xs:enumeration value="tests"/>
+													<xs:enumeration value="resources"/>
+												</xs:restriction>
+											</xs:simpleType>
+										</xs:element>
+										<xs:element name="filetype">
+											<xs:annotation>
+												<xs:documentation>extension of the file (osm, rb, etc)</xs:documentation>
+											</xs:annotation>
+											<xs:simpleType>
+												<xs:restriction base="xs:string">
+													<xs:enumeration value="resource"/>
+													<xs:enumeration value="test"/>
+													<xs:enumeration value="script"/>
+												</xs:restriction>
+											</xs:simpleType>
+										</xs:element>
+										<xs:element name="checksum" type="xs:string"/>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+</xs:schema>
diff --git a/src/utilities/xml/resources/bcl/measure_v3.0.xsd b/src/utilities/xml/resources/bcl/measure_v3.0.xsd
new file mode 100644
index 00000000000..4f3ccc1dab2
--- /dev/null
+++ b/src/utilities/xml/resources/bcl/measure_v3.0.xsd
@@ -0,0 +1,503 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSpy v2016 (x64) (http://www.altova.com) by kflemin (NREL) -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:annotation>
+		<xs:documentation>Measure.xsd describes the measures that are in the building component library or NREL analysis platform library.</xs:documentation>
+	</xs:annotation>
+	<xs:element name="schema_version" fixed="3.0">
+		<xs:annotation>
+			<xs:documentation>schema version</xs:documentation>
+		</xs:annotation>
+		<xs:simpleType>
+			<xs:restriction base="xs:string"/>
+		</xs:simpleType>
+	</xs:element>
+	<xs:element name="uid" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>universally unique identifier which does not chage</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="version_id" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>identifier which changes each time a new version is created</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="version_modified">
+		<xs:annotation>
+			<xs:documentation>timestamp at which the current version_id was created</xs:documentation>
+		</xs:annotation>
+		<xs:simpleType>
+			<xs:restriction base="xs:string">
+				<xs:pattern value="[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+				<xs:pattern value="[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+			</xs:restriction>
+		</xs:simpleType>
+	</xs:element>
+	<xs:element name="xml_checksum" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>checksum of selected xml elements and attributes, used to detect changes to the xml</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="error">
+		<xs:annotation>
+			<xs:documentation>record an error with this component or measure</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>snake cased machine readable name</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="display_name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>user facing name</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="description" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>user facing description</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="modeler_description" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>technical description of implementation details</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="class_name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>for measures only. name of the Ruby class implementing a measure</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="arguments">
+		<xs:annotation>
+			<xs:documentation>for measures only. arguments are computed based on a particular model and passed to the measure at run time.  actual values passed to the measure at run time are not captured here, only properties of the arguments </xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="argument" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element ref="name"/>
+							<xs:element ref="display_name"/>
+							<xs:element name="short_name" minOccurs="0"/>
+							<xs:element ref="description" minOccurs="0"/>
+							<xs:element name="type">
+								<xs:annotation>
+									<xs:documentation>type of the argument</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="Boolean"/>
+										<xs:enumeration value="Double"/>
+										<xs:enumeration value="Integer"/>
+										<xs:enumeration value="String"/>
+										<xs:enumeration value="Choice"/>
+										<xs:enumeration value="Path"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>units of the argument value in format parsable by OpenStudio::convert</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="required" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>true if the argument is required in order for the measure to run</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="model_dependent" type="xs:boolean" default="false">
+								<xs:annotation>
+									<xs:documentation>true if any of this argument's properties depend on the specific model used.  default_value, choice_values, min_value, and max_value will not be populated for dynamic arguments</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="default_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>default value for the argument</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="choices" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>list of allowable values</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="choice" maxOccurs="unbounded">
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="value" type="xs:anySimpleType">
+														<xs:annotation>
+															<xs:documentation>allowable value</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="display_name" type="xs:string">
+														<xs:annotation>
+															<xs:documentation>user facing name for value</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="min_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>minimum value</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="max_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>maximum value</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="masterguide_csi_values">
+		<xs:annotation>
+			<xs:documentation>for components only. values from the MASTERSPEC</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="masterguide_csi_value" maxOccurs="unbounded"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="source">
+		<xs:annotation>
+			<xs:documentation>for components only. source of the data (the origin of the component information)</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence minOccurs="0">
+				<xs:element name="manufacturer" type="xs:string" minOccurs="0"/>
+				<xs:element name="model" minOccurs="0"/>
+				<xs:element name="serial_no" minOccurs="0"/>
+				<xs:element name="year" minOccurs="0"/>
+				<xs:element name="url" minOccurs="0"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="provenances">
+		<xs:annotation>
+			<xs:documentation>provenance is used to enter author information.  </xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="provenance" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="author" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>author who uploaded the content, will be equal to the user account on the bcl site</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="datetime">
+								<xs:annotation>
+									<xs:documentation>date content was uploaded</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:pattern value="[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+										<xs:pattern value="[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[01])T(([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="comment" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>general comment</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="tags">
+		<xs:annotation>
+			<xs:documentation>tags are used to classify the content using the appropriate taxonomy.  currently only one tag per piece of content is supported.</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="tag" type="xs:string" maxOccurs="unbounded"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="attributes">
+		<xs:annotation>
+			<xs:documentation>attributes are descriptors of the content.  attributes should be found in the corresponding taxonomy</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="attribute" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="name" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>user facing attribute name (should be found in appropriate taxonomy)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="value" type="xs:anySimpleType"/>
+							<xs:element name="datatype">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="float"/>
+										<xs:enumeration value="integer"/>
+										<xs:enumeration value="string"/>
+										<xs:enumeration value="boolean"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="files">
+		<xs:annotation>
+			<xs:documentation>files lists details on all of the files associated with this piece content</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="file" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="version" minOccurs="0">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="software_program" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>software program the file is associated with</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="identifier" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>version of software program that this file is associated with</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="min_compatible" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>minimum version of the software this file is compatible with, if not specified assumed to be the version identifier</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="max_compatible" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>maximum version of the software this file is compatible with, if not specified assumed to be any version min_compatible or higher</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="filename" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>name of the file</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="filetype" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>ies, idf, </xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="usage_type">
+								<xs:annotation>
+									<xs:documentation>identifies the directory to search for the file in </xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="script"/>
+										<xs:enumeration value="test"/>
+										<xs:enumeration value="resource"/>
+										<xs:enumeration value="doc"/>
+										<xs:enumeration value="license"/>
+										<xs:enumeration value="readme"/>
+										<xs:enumeration value="readmeerb"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="checksum" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>checksum of the file as computed by OpenStudio::checksum</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="costs">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="cost" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="instance_name" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>name of cost for reference</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="cost_type">
+								<xs:annotation>
+									<xs:documentation>type of cost, includes low, high, average, estimate, etc</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="low"/>
+										<xs:enumeration value="high"/>
+										<xs:enumeration value="average"/>
+										<xs:enumeration value="estimate"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="category">
+								<xs:annotation>
+									<xs:documentation>ex:  operations and maintenance cost, salvage cost, materials cost, installation cost, upgrade cost, etc.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="value" type="xs:float">
+								<xs:annotation>
+									<xs:documentation>cost value based on the supplemntal fields</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="units" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>cost unit. If blank, absolute cost is assumed. ex:  $/ft2, $/person, etc.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="interval" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>number describing the interval on which this cost is incurred.  ex:  1, 6, 12.  Use 0 for onetime costs</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="interval_units" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>interval units. ex:  day, month, year, etc.</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="year(s)"/>
+										<xs:enumeration value="month(s)"/>
+										<xs:enumeration value="day(s)"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="year" type="xs:int" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>source year of the costs</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="start_year" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>define when this cost will start to incur. Useful when you may not want maintenance costs to start until n years after construction</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="end_year" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>define whne this cost will stop incurring.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="location" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>the geographic location where the component was costed (i.e. national, colorado, denver, etc).  By default all values should be national averages.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="currency" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>the currency of the cost.  If blank, USD is assumed.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="source" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>origin from which the cost data came</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="reference_component_name" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>display name of reference component prior to retrofit (for marginal costs)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="reference_component_id" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>ID of reference component prior to retrofit (for marginal costs)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="measure">
+		<xs:annotation>
+			<xs:documentation>root element defining a measure</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element ref="schema_version"/>
+				<xs:element ref="error" minOccurs="0"/>
+				<xs:element ref="name"/>
+				<xs:element ref="uid"/>
+				<xs:element ref="version_id"/>
+				<xs:element ref="version_modified" minOccurs="0"/>
+				<xs:element ref="xml_checksum"/>
+				<xs:element ref="class_name"/>
+				<xs:element ref="display_name"/>
+				<xs:element ref="description"/>
+				<xs:element ref="modeler_description"/>
+				<xs:element ref="arguments"/>
+				<xs:element ref="outputs"/>
+				<xs:element ref="provenances"/>
+				<xs:element ref="tags"/>
+				<xs:element ref="attributes"/>
+				<xs:element ref="files"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="outputs">
+		<xs:annotation>
+			<xs:documentation>for measures ony.  Outputs represent the output values to include in analysis results</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="output" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element ref="name"/>
+							<xs:element ref="display_name"/>
+							<xs:element name="short_name" type="xs:string" minOccurs="0"/>
+							<xs:element ref="description" minOccurs="0"/>
+							<xs:element name="type">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="Boolean"/>
+										<xs:enumeration value="Double"/>
+										<xs:enumeration value="Integer"/>
+										<xs:enumeration value="String"/>
+										<xs:enumeration value="Choice"/>
+										<xs:enumeration value="Path"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>units of the output value in format parsable by OpenStudio::convert</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="model_dependent" type="xs:boolean" default="false">
+								<xs:annotation>
+									<xs:documentation>true if any of this output's properties depend on the specific model used.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+</xs:schema>
diff --git a/src/utilities/xml/resources/bcl/measure_v3.1.xsd b/src/utilities/xml/resources/bcl/measure_v3.1.xsd
new file mode 100644
index 00000000000..f7f9d138cd9
--- /dev/null
+++ b/src/utilities/xml/resources/bcl/measure_v3.1.xsd
@@ -0,0 +1,491 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSpy v2016 (x64) (http://www.altova.com) by kflemin (NREL) -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+	<xs:annotation>
+		<xs:documentation>Measure.xsd describes the measures that are in the building component library or NREL analysis platform library.</xs:documentation>
+	</xs:annotation>
+	<xs:element name="schema_version" fixed="3.1">
+		<xs:annotation>
+			<xs:documentation>schema version</xs:documentation>
+		</xs:annotation>
+		<xs:simpleType>
+			<xs:restriction base="xs:string"/>
+		</xs:simpleType>
+	</xs:element>
+	<xs:element name="uid" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>universally unique identifier which does not chage</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="version_id" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>identifier which changes each time a new version is created</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="version_modified" type="xs:dateTime">
+		<xs:annotation>
+			<xs:documentation>timestamp at which the current version_id was created</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="xml_checksum" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>checksum of selected xml elements and attributes, used to detect changes to the xml</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="error">
+		<xs:annotation>
+			<xs:documentation>record an error with this component or measure</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>snake cased machine readable name</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="display_name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>user facing name</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="description" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>user facing description</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="modeler_description" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>technical description of implementation details</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="class_name" type="xs:string">
+		<xs:annotation>
+			<xs:documentation>for measures only. name of the Ruby class implementing a measure</xs:documentation>
+		</xs:annotation>
+	</xs:element>
+	<xs:element name="arguments">
+		<xs:annotation>
+			<xs:documentation>for measures only. arguments are computed based on a particular model and passed to the measure at run time.  actual values passed to the measure at run time are not captured here, only properties of the arguments </xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="argument" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element ref="name"/>
+							<xs:element ref="display_name"/>
+							<xs:element name="short_name" minOccurs="0"/>
+							<xs:element ref="description" minOccurs="0"/>
+							<xs:element name="type">
+								<xs:annotation>
+									<xs:documentation>type of the argument</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="Boolean"/>
+										<xs:enumeration value="Double"/>
+										<xs:enumeration value="Integer"/>
+										<xs:enumeration value="String"/>
+										<xs:enumeration value="Choice"/>
+										<xs:enumeration value="Path"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>units of the argument value in format parsable by OpenStudio::convert</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="required" type="xs:boolean">
+								<xs:annotation>
+									<xs:documentation>true if the argument is required in order for the measure to run</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="model_dependent" type="xs:boolean" default="false">
+								<xs:annotation>
+									<xs:documentation>true if any of this argument's properties depend on the specific model used.  default_value, choice_values, min_value, and max_value will not be populated for dynamic arguments</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="default_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>default value for the argument</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="choices" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>list of allowable values</xs:documentation>
+								</xs:annotation>
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="choice" maxOccurs="unbounded">
+											<xs:complexType>
+												<xs:sequence>
+													<xs:element name="value" type="xs:anySimpleType">
+														<xs:annotation>
+															<xs:documentation>allowable value</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+													<xs:element name="display_name" type="xs:string">
+														<xs:annotation>
+															<xs:documentation>user facing name for value</xs:documentation>
+														</xs:annotation>
+													</xs:element>
+												</xs:sequence>
+											</xs:complexType>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="min_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>minimum value</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="max_value" type="xs:anySimpleType" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>maximum value</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="masterguide_csi_values">
+		<xs:annotation>
+			<xs:documentation>for components only. values from the MASTERSPEC</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="masterguide_csi_value" maxOccurs="unbounded"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="source">
+		<xs:annotation>
+			<xs:documentation>for components only. source of the data (the origin of the component information)</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence minOccurs="0">
+				<xs:element name="manufacturer" type="xs:string" minOccurs="0"/>
+				<xs:element name="model" minOccurs="0"/>
+				<xs:element name="serial_no" minOccurs="0"/>
+				<xs:element name="year" minOccurs="0"/>
+				<xs:element name="url" minOccurs="0"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="provenances">
+		<xs:annotation>
+			<xs:documentation>provenance is used to enter author information.  </xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="provenance" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="author" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>author who uploaded the content, will be equal to the user account on the bcl site</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="datetime" type="xs:dateTime">
+								<xs:annotation>
+									<xs:documentation>date content was uploaded</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="comment" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>general comment</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="tags">
+		<xs:annotation>
+			<xs:documentation>tags are used to classify the content using the appropriate taxonomy.  currently only one tag per piece of content is supported.</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="tag" type="xs:string" maxOccurs="unbounded"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="attributes">
+		<xs:annotation>
+			<xs:documentation>attributes are descriptors of the content.  attributes should be found in the corresponding taxonomy</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="attribute" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="name" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>user facing attribute name (should be found in appropriate taxonomy)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="value" type="xs:anySimpleType"/>
+							<xs:element name="datatype">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="float"/>
+										<xs:enumeration value="integer"/>
+										<xs:enumeration value="string"/>
+										<xs:enumeration value="boolean"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0"/>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="files">
+		<xs:annotation>
+			<xs:documentation>files lists details on all of the files associated with this piece content</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="file" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="version" minOccurs="0">
+								<xs:complexType>
+									<xs:sequence>
+										<xs:element name="software_program" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>software program the file is associated with</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="identifier" type="xs:string">
+											<xs:annotation>
+												<xs:documentation>version of software program that this file is associated with</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="min_compatible" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>minimum version of the software this file is compatible with, if not specified assumed to be the version identifier</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+										<xs:element name="max_compatible" minOccurs="0">
+											<xs:annotation>
+												<xs:documentation>maximum version of the software this file is compatible with, if not specified assumed to be any version min_compatible or higher</xs:documentation>
+											</xs:annotation>
+										</xs:element>
+									</xs:sequence>
+								</xs:complexType>
+							</xs:element>
+							<xs:element name="filename" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>name of the file</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="filetype" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>ies, idf, </xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="usage_type">
+								<xs:annotation>
+									<xs:documentation>identifies the directory to search for the file in </xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="script"/>
+										<xs:enumeration value="test"/>
+										<xs:enumeration value="resource"/>
+										<xs:enumeration value="doc"/>
+										<xs:enumeration value="license"/>
+										<xs:enumeration value="readme"/>
+										<xs:enumeration value="readmeerb"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="checksum" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>checksum of the file as computed by OpenStudio::checksum</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="costs">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="cost" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element name="instance_name" type="xs:string">
+								<xs:annotation>
+									<xs:documentation>name of cost for reference</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="cost_type">
+								<xs:annotation>
+									<xs:documentation>type of cost, includes low, high, average, estimate, etc</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="low"/>
+										<xs:enumeration value="high"/>
+										<xs:enumeration value="average"/>
+										<xs:enumeration value="estimate"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="category">
+								<xs:annotation>
+									<xs:documentation>ex:  operations and maintenance cost, salvage cost, materials cost, installation cost, upgrade cost, etc.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="value" type="xs:float">
+								<xs:annotation>
+									<xs:documentation>cost value based on the supplemntal fields</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="units" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>cost unit. If blank, absolute cost is assumed. ex:  $/ft2, $/person, etc.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="interval" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>number describing the interval on which this cost is incurred.  ex:  1, 6, 12.  Use 0 for onetime costs</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="interval_units" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>interval units. ex:  day, month, year, etc.</xs:documentation>
+								</xs:annotation>
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="year(s)"/>
+										<xs:enumeration value="month(s)"/>
+										<xs:enumeration value="day(s)"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="year" type="xs:int" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>source year of the costs</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="start_year" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>define when this cost will start to incur. Useful when you may not want maintenance costs to start until n years after construction</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="end_year" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>define whne this cost will stop incurring.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="location" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>the geographic location where the component was costed (i.e. national, colorado, denver, etc).  By default all values should be national averages.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="currency" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>the currency of the cost.  If blank, USD is assumed.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="source" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>origin from which the cost data came</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="reference_component_name" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>display name of reference component prior to retrofit (for marginal costs)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="reference_component_id" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>ID of reference component prior to retrofit (for marginal costs)</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="measure">
+		<xs:annotation>
+			<xs:documentation>root element defining a measure</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element ref="schema_version"/>
+				<xs:element ref="error" minOccurs="0"/>
+				<xs:element ref="name"/>
+				<xs:element ref="uid"/>
+				<xs:element ref="version_id"/>
+				<xs:element ref="version_modified" minOccurs="0"/>
+				<xs:element ref="xml_checksum"/>
+				<xs:element ref="class_name"/>
+				<xs:element ref="display_name"/>
+				<xs:element ref="description"/>
+				<xs:element ref="modeler_description"/>
+				<xs:element ref="arguments"/>
+				<xs:element ref="outputs"/>
+				<xs:element ref="provenances"/>
+				<xs:element ref="tags"/>
+				<xs:element ref="attributes"/>
+				<xs:element ref="files"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="outputs">
+		<xs:annotation>
+			<xs:documentation>for measures ony.  Outputs represent the output values to include in analysis results</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="output" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:sequence>
+							<xs:element ref="name"/>
+							<xs:element ref="display_name"/>
+							<xs:element name="short_name" type="xs:string" minOccurs="0"/>
+							<xs:element ref="description" minOccurs="0"/>
+							<xs:element name="type">
+								<xs:simpleType>
+									<xs:restriction base="xs:string">
+										<xs:enumeration value="Boolean"/>
+										<xs:enumeration value="Double"/>
+										<xs:enumeration value="Integer"/>
+										<xs:enumeration value="String"/>
+										<xs:enumeration value="Choice"/>
+										<xs:enumeration value="Path"/>
+									</xs:restriction>
+								</xs:simpleType>
+							</xs:element>
+							<xs:element name="units" type="xs:string" minOccurs="0">
+								<xs:annotation>
+									<xs:documentation>units of the output value in format parsable by OpenStudio::convert</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+							<xs:element name="model_dependent" type="xs:boolean" default="false">
+								<xs:annotation>
+									<xs:documentation>true if any of this output's properties depend on the specific model used.</xs:documentation>
+								</xs:annotation>
+							</xs:element>
+						</xs:sequence>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+</xs:schema>


Test patch:
diff --git a/src/cli/test/logger_test.py b/src/cli/test/logger_test.py
index ffa0ccdf601..e3bf307f519 100644
--- a/src/cli/test/logger_test.py
+++ b/src/cli/test/logger_test.py
@@ -12,7 +12,7 @@
 handler.setFormatter(formatter)
 logger.addHandler(handler)
 
-openstudio.Logger_instance().standardOutLogger().setLogLevel(openstudio.Error)
+openstudio.Logger.instance().standardOutLogger().setLogLevel(openstudio.Error)
 
 logger.info("STDOUT Info")
 logger.warning("STDOUT Warn")
diff --git a/src/utilities/bcl/test/BCLFixture.cpp b/src/utilities/bcl/test/BCLFixture.cpp
index 622b16d269d..c2bce328ab4 100644
--- a/src/utilities/bcl/test/BCLFixture.cpp
+++ b/src/utilities/bcl/test/BCLFixture.cpp
@@ -32,6 +32,9 @@
 #include "../LocalBCL.hpp"
 #include "../../core/ApplicationPathHelpers.hpp"
 
+#include <algorithm>
+#include <regex>
+
 using openstudio::LocalBCL;
 using openstudio::Logger;
 using openstudio::toPath;
@@ -94,6 +97,41 @@ void BCLFixture::TearDownTestSuite() {
   logFile->disable();
 }
 
+::testing::AssertionResult BCLFixture::checkLogMessagesContain(const std::vector<openstudio::LogMessage>& logMessages,
+                                                               const std::vector<std::string>& searchStrings, bool use_regex) {
+
+  std::vector<std::string> logStrings;
+  std::transform(logMessages.cbegin(), logMessages.cend(), std::back_inserter(logStrings),
+                 [](const auto& logMessage) { return logMessage.logMessage(); });
+
+  std::stringstream ss;
+  int not_found = 0;
+
+  for (const std::string& searchString : searchStrings) {
+    bool match_found = false;
+    for (const std::string& logString : logStrings) {
+      if (use_regex) {
+        match_found = std::regex_match(logString, std::regex(searchString));
+      } else {
+        match_found = logString.find(searchString) != std::string::npos;
+      }
+      if (match_found) {
+        break;
+      }
+    }
+    if (!match_found) {
+      ++not_found;
+      ss << " * " << not_found << ": '" << searchString << "'\n";
+    }
+  }
+
+  if (not_found == 0) {
+    return ::testing::AssertionSuccess();
+  } else {
+    return ::testing::AssertionFailure() << "Could not find " << not_found << " messages:\n" << ss.str();
+  }
+}
+
 // define static storage
 boost::optional<openstudio::FileLogSink> BCLFixture::logFile;
 // these are Dan's API keys labelled under "Testing", delete when there is a better way to do this
diff --git a/src/utilities/bcl/test/BCLFixture.hpp b/src/utilities/bcl/test/BCLFixture.hpp
index ca32b045305..f7dd839de0b 100644
--- a/src/utilities/bcl/test/BCLFixture.hpp
+++ b/src/utilities/bcl/test/BCLFixture.hpp
@@ -37,6 +37,9 @@
 #include "../../core/Logger.hpp"
 #include "../../core/FileLogSink.hpp"
 
+#include <string>
+#include <vector>
+
 class BCLFixture : public ::testing::Test
 {
  protected:
@@ -55,6 +58,9 @@ class BCLFixture : public ::testing::Test
   // set up logging
   REGISTER_LOGGER("BCLFixture");
 
+  static ::testing::AssertionResult checkLogMessagesContain(const std::vector<openstudio::LogMessage>& logMessages,
+                                                            const std::vector<std::string>& searchStrings, bool use_regex = false);
+
  public:
   // This is assigned in SetUp, per test, so doesn't have to be static
   std::string prodAuthKey;
diff --git a/src/utilities/bcl/test/BCLXML_GTest.cpp b/src/utilities/bcl/test/BCLXML_GTest.cpp
index efe2842491b..bba96d38f95 100644
--- a/src/utilities/bcl/test/BCLXML_GTest.cpp
+++ b/src/utilities/bcl/test/BCLXML_GTest.cpp
@@ -31,6 +31,10 @@
 #include "BCLFixture.hpp"
 
 #include "../BCLXML.hpp"
+#include "../BCLFileReference.hpp"
+#include "../../xml/XMLValidator.hpp"
+
+#include <pugixml.hpp>
 
 using namespace openstudio;
 
@@ -113,14 +117,109 @@ TEST_F(BCLFixture, BCLXML_New) {
   EXPECT_EQ(versionId, bclXML.versionId());
 
   versionId = bclXML.versionId();
-  openstudio::path path = toPath("./measure.xml");
-  EXPECT_TRUE(bclXML.saveAs(path));
+  openstudio::path xmlPath = toPath("./measure.xml");
+  EXPECT_TRUE(bclXML.saveAs(xmlPath));
   EXPECT_NE(versionId, bclXML.versionId());
 
   versionId = bclXML.versionId();
   EXPECT_TRUE(bclXML.save());
   EXPECT_EQ(versionId, bclXML.versionId());
 
-  boost::optional<BCLXML> copy = BCLXML::load(path);
+  // Validate any newly written XML
+  boost::optional<BCLXML> copy = BCLXML::load(xmlPath);
   ASSERT_TRUE(copy);
+
+  auto bclXMLValidator = XMLValidator::bclXMLValidator(BCLXMLType::MeasureXML, BCLXML::currentSchemaVersion());
+  EXPECT_TRUE(bclXMLValidator.validate(xmlPath));
+  EXPECT_EQ(0, bclXMLValidator.errors().size()) << [&bclXMLValidator]() {
+    std::string s;
+    for (auto& logMessage : bclXMLValidator.errors()) {
+      s += logMessage.logMessage() + "\n";
+    }
+    return s;
+  }();
+  EXPECT_EQ(0, bclXMLValidator.warnings().size());
+}
+
+TEST_F(BCLFixture, BCLXML_sorted_files) {
+
+  BCLXML bclXML(BCLXMLType::MeasureXML);
+
+  const openstudio::path testDir("my_measure");
+
+  const BCLFileReference ref1(testDir, "fileA", true);
+  const BCLFileReference ref2(testDir, "fileC", true);
+  const BCLFileReference ref3(testDir, "fileB", true);
+  const BCLFileReference ref4(testDir, "fileD", true);
+
+  bclXML.addFile(ref1);
+  bclXML.addFile(ref2);
+  bclXML.addFile(ref3);
+  bclXML.addFile(ref4);
+
+  const openstudio::path xmlPath = resourcesPath() / toPath("utilities/BCL/sorted.xml");
+  bclXML.saveAs(xmlPath);
+
+  pugi::xml_document xmlDoc;
+  openstudio::filesystem::ifstream file(xmlPath);
+  ASSERT_TRUE(file.is_open());
+  ASSERT_TRUE(xmlDoc.load(file));
+  auto measureElement = xmlDoc.child("measure");
+  auto xmlFilesElement = measureElement.child("files");
+  std::vector<std::string> savedFiles;
+  for (auto& fileElement : xmlFilesElement.children("file")) {
+    if (!fileElement.first_child().empty()) {
+      // Filename is a relative path, and if usageType is doc/resource/test it omits the subdirectory
+      savedFiles.emplace_back(fileElement.child("filename").text().as_string());
+    }
+  }
+
+  ASSERT_EQ(4, savedFiles.size());
+  EXPECT_EQ("fileA", savedFiles[0]);
+  EXPECT_EQ("fileB", savedFiles[1]);
+  EXPECT_EQ("fileC", savedFiles[2]);
+  EXPECT_EQ("fileD", savedFiles[3]);
+}
+
+TEST_F(BCLFixture, BCLXML_validation_historical) {
+
+  // This has an ISO8601 datetime instead of a valid xs:dateTime
+  // <version_modified>20170316T161836Z</version_modified>
+  const openstudio::path xmlPath = resourcesPath() / toPath("/utilities/BCL/Measures/v3/IncreaseRoofRValue/measure.xml");
+  const boost::optional<BCLXML> bclXML = BCLXML::load(xmlPath);
+  ASSERT_TRUE(bclXML);
+
+  // Validate with 3.0 schema: it should work
+  {
+    auto bclXMLValidator = XMLValidator::bclXMLValidator(BCLXMLType::MeasureXML, VersionString(3, 0));
+    EXPECT_TRUE(bclXMLValidator.validate(xmlPath));
+    EXPECT_EQ(0, bclXMLValidator.errors().size()) << [&bclXMLValidator]() {
+      std::string s;
+      for (auto& logMessage : bclXMLValidator.errors()) {
+        s += logMessage.logMessage() + "\n";
+      }
+      return s;
+    }();
+    EXPECT_EQ(0, bclXMLValidator.warnings().size());
+  }
+
+  // Validate with 3.1 schema: it shouldn't work
+  {
+    auto bclXMLValidator = XMLValidator::bclXMLValidator(BCLXMLType::MeasureXML, VersionString(3, 1));
+    EXPECT_FALSE(bclXMLValidator.validate(xmlPath));
+
+    EXPECT_EQ(2, bclXMLValidator.errors().size()) << [&bclXMLValidator]() {
+      std::string s;
+      for (auto& logMessage : bclXMLValidator.errors()) {
+        s += logMessage.logMessage() + "\n";
+      }
+      return s;
+    }();
+    EXPECT_TRUE(checkLogMessagesContain(bclXMLValidator.errors(),
+                                        {
+                                          "Element 'schema_version': The actual value '3.0' does not match the fixed value constraint '3.1'",
+                                          "Element 'version_modified': '20170316T161836Z' is not a valid value of the atomic type 'xs:dateTime",
+                                        }));
+    EXPECT_EQ(0, bclXMLValidator.warnings().size());
+  }
 }