diff --git a/OpenXLSX/sources/XLStyles.cpp b/OpenXLSX/sources/XLStyles.cpp index f546c38..1220461 100644 --- a/OpenXLSX/sources/XLStyles.cpp +++ b/OpenXLSX/sources/XLStyles.cpp @@ -701,31 +701,16 @@ XLColor XLFont::fontColor() const /** * @details getter functions: return the font's bold, italic, underline, strikethrough status */ -bool XLFont::bold() const { return appendAndGetNodeAttribute(*m_fontNode, "b", "val", "false").as_bool() ; } -bool XLFont::italic() const { return appendAndGetNodeAttribute(*m_fontNode, "i", "val", "false").as_bool() ; } -bool XLFont::strikethrough() const { - if (m_fontNode->empty()) return false; - XMLNode strikeNode = m_fontNode->child("strike"); - if( strikeNode.empty() ) // no strike node: return false - return false; - - // if execution gets here: strike node is not empty - XMLAttribute valAttr = strikeNode.attribute("val"); - if( valAttr.empty() ) { // if no val attribute exists: default to true as per specification - appendAndSetAttribute(strikeNode, "val", "true" ); // explicitly create & set attribute - return true; - } - - // if execution gets here: attribute val exists - return valAttr.as_bool(); // return attribute value -} +bool XLFont::bold() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "b", "val"); } +bool XLFont::italic() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "i", "val"); } +bool XLFont::strikethrough() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "strike", "val"); } XLUnderlineStyle XLFont::underline() const { return XLUnderlineStyleFromString (appendAndGetNodeAttribute(*m_fontNode, "u", "val", "" ).value() ); } XLFontSchemeStyle XLFont::scheme() const { return XLFontSchemeStyleFromString (appendAndGetNodeAttribute(*m_fontNode, "scheme", "val", "" ).value() ); } XLVerticalAlignRunStyle XLFont::vertAlign() const { return XLVerticalAlignRunStyleFromString(appendAndGetNodeAttribute(*m_fontNode, "vertAlign", "val", "" ).value() ); } -bool XLFont::outline() const { return appendAndGetNodeAttribute(*m_fontNode, "outline", "val", "false").as_bool() ; } -bool XLFont::shadow() const { return appendAndGetNodeAttribute(*m_fontNode, "shadow", "val", "false").as_bool() ; } -bool XLFont::condense() const { return appendAndGetNodeAttribute(*m_fontNode, "condense", "val", "false").as_bool() ; } -bool XLFont::extend() const { return appendAndGetNodeAttribute(*m_fontNode, "extend", "val", "false").as_bool() ; } +bool XLFont::outline() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "outline", "val"); } +bool XLFont::shadow() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "shadow", "val"); } +bool XLFont::condense() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "condense", "val"); } +bool XLFont::extend() const { return getBoolAttributeWhenOmittedMeansTrue(*m_fontNode, "extend", "val"); } /** * @details Setter functions diff --git a/OpenXLSX/sources/utilities/XLUtilities.hpp b/OpenXLSX/sources/utilities/XLUtilities.hpp index 66321ed..8c4a134 100644 --- a/OpenXLSX/sources/utilities/XLUtilities.hpp +++ b/OpenXLSX/sources/utilities/XLUtilities.hpp @@ -450,6 +450,30 @@ namespace OpenXLSX if (removeAttributes) node.remove_attributes(); return appendAndSetAttribute(node, attrName, attrVal); } + + /** + * @brief special bool attribute getter function for tags that should have a val="true" or val="false" attribute, + * but when omitted shall default to "true" + * @param parent node under which tagName shall be found + * @param tagName name of the boolean tag to evaluate + * @param attrName (default: "val") name of boolean attribute that shall default to true + * @returns true if parent & tagName exist, and attribute with attrName is either omitted or as_bool() returns true. Otherwise return false + * @note this will create and explicitly set attrName if omitted + */ + inline bool getBoolAttributeWhenOmittedMeansTrue( XMLNode & parent, std::string const & tagName, std::string const & attrName = "val" ) + { + if (parent.empty()) return false; // can't do anything + XMLNode tagNode = parent.child(tagName.c_str()); + if( tagNode.empty() ) return false; // if tag does not exist: return false + XMLAttribute valAttr = tagNode.attribute(attrName.c_str()); + if( valAttr.empty() ) { // if no attribute with attrName exists: default to true + appendAndSetAttribute(tagNode, attrName, "true" ); // explicitly create & set attribute + return true; + } + // if execution gets here: attribute with attrName exists + return valAttr.as_bool(); // return attribute value + } + } // namespace OpenXLSX #endif // OPENXLSX_XLUTILITIES_HPP diff --git a/README.md b/README.md index 97e4cf0..93906fb 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,10 @@ Microsoft Excel® files, with the .xlsx format. As the heading says - the latest "Release" that is shown on https://github.com/troldal/OpenXLSX/releases is from 2021-11-06, and severely outdated - please pull / download the latest SW version directly from the repository in its current state. Link for those that do not want to use ```git```: https://github.com/troldal/OpenXLSX/archive/refs/heads/master.zip +## (aral-matrix) 23 March 2025 - XLStyles: get bool settings when omitted attribute shall default to true - addresses #347 +* added function ```getBoolAttributeWhenOmittedMeansTrue``` to ```XLUtilities``` +* ```XLStyles``` ```XLFont```: changed bool getter functions to return ```true``` when tag exists, but attribute ```val``` is omitted, to be in line with OOXML spec. This addresses https://github.com/troldal/OpenXLSX/issues/347. Affected getters: ```bold()```, ```italic()```, ```strikethrough()```, ```outline()```, ```shadow()```, ```condense()```, ```extend()``` + ## (aral-matrix) 16 March 2025 - XLSheet::findCell added to address #333, setting an XLFormula to an empty string now deletes the formula * added function(s) ```XLSheet::findCell``` that allow to try and fetch a cell without creating the row/cell XML (like the non-creating XLCellIterator). This function complements ```XLSheet::cell``` (which always creates the XML cell node and returns a valid object) * after using ```findCell```, the returned ```XLCellAssignable::empty()``` method must be checked to ensure success before accessing any cell properties