tdf#115376: distinguish ordered/unordered list in epub export

I thought I could just mimick the existing mechanism to retrieve list styles
but a list style is defined with:
- 1 "text:list-style" tag which only contains the attribute "style:name"
- several (most of times 10) "text:list-level-style-number" or "text:list-level-style-bullet" subtags
Remark: these subtags contains other elements but we haven't dealt with them

I'd have hoped there was a simpler way but I haven't found it.

Change-Id: I438dbca7769f3d4110818df414f0997886180c59
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207020
Tested-by: Jenkins
Reviewed-by: Julien Nabet <serval2412@yahoo.fr>
This commit is contained in:
Julien Nabet
2026-06-20 12:57:41 +02:00
parent 35611998e3
commit 2c81d753ef
9 changed files with 175 additions and 12 deletions
+2 -2
View File
@@ -496,10 +496,10 @@ CPPUNIT_TEST_FIXTURE(EPUBExportTest, testList)
xmlDocUniquePtr mpXmlDoc = parseExport(u"OEBPS/sections/section0001.xhtml"_ustr);
// This was "C", i.e. in-list content was ignored.
assertXPathContent(mpXmlDoc, "//xhtml:ol[1]/xhtml:li[1]/xhtml:p[1]/xhtml:span", u"B");
assertXPathContent(mpXmlDoc, "//xhtml:ul[1]/xhtml:li[1]/xhtml:p[1]/xhtml:span", u"B");
// Test nested list content.
assertXPathContent(
mpXmlDoc, "//xhtml:ol[2]/xhtml:li[1]/xhtml:ol[1]/xhtml:li[1]/xhtml:p[1]/xhtml:span", u"F");
mpXmlDoc, "//xhtml:ul[2]/xhtml:li[1]/xhtml:ol[1]/xhtml:li[1]/xhtml:p[1]/xhtml:span", u"F");
}
CPPUNIT_TEST_FIXTURE(EPUBExportTest, testImage)
@@ -17,6 +17,9 @@ using namespace com::sun::star;
namespace writerperfect::exp
{
int XMLTextListContext::nLevel = 0;
OUString XMLTextListContext::aStyleName = "";
XMLTextListContext::XMLTextListContext(XMLImport& rImport)
: XMLImportContext(rImport)
{
@@ -31,19 +34,67 @@ rtl::Reference<XMLImportContext> XMLTextListContext::CreateChildContext(
}
void XMLTextListContext::startElement(
const OUString& /*rName*/,
const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/)
const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs)
{
// TODO we should find a way to know if we're in the case of ordered or unordered list
// in second case, we should call "openUnorderedListLevel"
GetImport().GetGenerator().openOrderedListLevel(librevenge::RVNGPropertyList());
++nLevel;
librevenge::RVNGPropertyList aPropertyList;
for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i)
{
const OUString aAttributeName = xAttribs->getNameByIndex(i);
const OUString aAttributeValue = xAttribs->getValueByIndex(i);
if (aAttributeName == "text:style-name")
{
aStyleName = aAttributeValue;
break;
}
}
// either we found a style name in the previous for loop
// or we are in a sublist which hasn't got a defined style-name
// so we use the last style-name, the one from the parent
// see XMLListPropertiesContext::startElement for an explanation about use of RVNGPropertyListVector
if (!aStyleName.isEmpty())
{
auto it = GetImport().GetAutomaticListStyles().find(aStyleName);
OString aKey = OUStringToOString(aStyleName, RTL_TEXTENCODING_UTF8);
const librevenge::RVNGProperty* propLevel = it->second.child(aKey.getStr());
if (propLevel)
{
const librevenge::RVNGPropertyListVector* pSubStylesVector
= static_cast<const librevenge::RVNGPropertyListVector*>(propLevel);
const librevenge::RVNGPropertyList& list = (*pSubStylesVector)[nLevel - 1];
const librevenge::RVNGProperty* p = list["style:num-format"];
if (p)
{
m_bIsOrderedList = true;
}
}
}
if (m_bIsOrderedList)
{
GetImport().GetGenerator().openOrderedListLevel(librevenge::RVNGPropertyList());
}
else
{
GetImport().GetGenerator().openUnorderedListLevel(librevenge::RVNGPropertyList());
}
}
void XMLTextListContext::endElement(const OUString& /*rName*/)
{
// TODO we should find a way to know if we're in the case of ordered or unordered list
// in second case, we should call "closeUnorderedListLevel"
GetImport().GetGenerator().closeOrderedListLevel();
--nLevel;
aStyleName = "";
if (m_bIsOrderedList)
{
GetImport().GetGenerator().closeOrderedListLevel();
}
else
{
GetImport().GetGenerator().closeUnorderedListLevel();
}
}
} // namespace writerperfect::exp
@@ -28,6 +28,16 @@ public:
const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/) override;
void SAL_CALL endElement(const OUString& rName) override;
private:
// this static variable will be incremented each time we open "text:list"
// and will be decremented each time we close "text:list"
static int nLevel;
// this static variable will keep last style name used for list
// since sublist can have no style:name attribute
// until we close the list
static OUString aStyleName;
bool m_bIsOrderedList = false;
};
} // namespace writerperfect::exp
+75 -1
View File
@@ -8,7 +8,6 @@
*/
#include "txtstyli.hxx"
#include "xmlfmt.hxx"
using namespace com::sun::star;
@@ -119,6 +118,74 @@ void XMLGraphicPropertiesContext::startElement(
}
}
namespace
{
/// Handler for <text:list-level-style-number> and <text:text:list-level-style-bullet>.
class XMLListPropertiesContext : public XMLImportContext
{
public:
XMLListPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle,
const OUString& rStyleName);
void SAL_CALL
startElement(const OUString& rName,
const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs) override;
private:
XMLStyleContext& mrStyle;
const OUString& mrStyleName;
};
}
XMLListPropertiesContext::XMLListPropertiesContext(XMLImport& rImport, XMLStyleContext& rStyle,
const OUString& rStyleName)
: XMLImportContext(rImport)
, mrStyle(rStyle)
, mrStyleName(rStyleName)
{
}
void XMLListPropertiesContext::startElement(
const OUString& /*rName*/, const css::uno::Reference<css::xml::sax::XAttributeList>& xAttribs)
{
OString aStyleName = OUStringToOString(mrStyleName, RTL_TEXTENCODING_UTF8);
// a list style is defined with:
// 1 "text:list-style" tag which only contains the attribute "style:name"
// several (most of times 10) "text:list-level-style-number" or "text:list-level-style-bullet" subtags
// remark: these subtags contains other elements but we haven't dealt with them
// anyway, that's why we need a RVNGPropertyListVector, this one will contains subtags
// all attributes of the a subtag will be in a RVNGPropertyList
// declare the vector for the current style
librevenge::RVNGPropertyListVector aStyleCurrentVector;
// check if there's an existing one and if it's the case, use it
const librevenge::RVNGProperty* pStyleProperty
= mrStyle.GetListPropertyList().child(aStyleName.getStr());
if (pStyleProperty)
{
const librevenge::RVNGPropertyListVector* pStyleVector
= static_cast<const librevenge::RVNGPropertyListVector*>(pStyleProperty);
aStyleCurrentVector = *pStyleVector;
}
// create a RVNGPropertyList for the subtag of a style
librevenge::RVNGPropertyList aCurrentPropertyList;
// save all attributes of the subtag
for (sal_Int16 i = 0; i < xAttribs->getLength(); ++i)
{
OString sName = OUStringToOString(xAttribs->getNameByIndex(i), RTL_TEXTENCODING_UTF8);
OString sValue = OUStringToOString(xAttribs->getValueByIndex(i), RTL_TEXTENCODING_UTF8);
aCurrentPropertyList.insert(sName.getStr(), sValue.getStr());
}
// now we can add the subtag in the vector
aStyleCurrentVector.append(aCurrentPropertyList);
// and insert/reinsert it in mrStyle.GetListPropertyList
mrStyle.GetListPropertyList().insert(aStyleName.getStr(), aStyleCurrentVector);
}
namespace
{
/// Handler for <style:page-layout-properties>.
@@ -325,6 +392,8 @@ rtl::Reference<XMLImportContext> XMLStyleContext::CreateChildContext(
return new XMLTablePropertiesContext(GetImport(), *this);
if (rName == "style:graphic-properties")
return new XMLGraphicPropertiesContext(GetImport(), *this);
if (rName == "text:list-level-style-number" || rName == "text:list-level-style-bullet")
return new XMLListPropertiesContext(GetImport(), *this, m_aName);
if (rName == "style:page-layout-properties")
return new XMLPageLayoutPropertiesContext(GetImport(), *this);
return nullptr;
@@ -348,6 +417,7 @@ void XMLStyleContext::startElement(
m_aTextPropertyList.insert(sName.getStr(), sValue.getStr());
m_aParagraphPropertyList.insert(sName.getStr(), sValue.getStr());
m_aGraphicPropertyList.insert(sName.getStr(), sValue.getStr());
m_aListPropertyList.insert(sName.getStr(), sValue.getStr());
m_aPageLayoutPropertyList.insert(sName.getStr(), sValue.getStr());
m_aMasterPagePropertyList.insert(sName.getStr(), sValue.getStr());
m_aTablePropertyList.insert(sName.getStr(), sValue.getStr());
@@ -373,6 +443,8 @@ void XMLStyleContext::endElement(const OUString& rName)
m_rStyles.GetCurrentTableStyles()[m_aName] = m_aTablePropertyList;
else if (m_aFamily == "graphic")
m_rStyles.GetCurrentGraphicStyles()[m_aName] = m_aGraphicPropertyList;
else if (rName == "text:list-style")
m_rStyles.GetCurrentListStyles()[m_aName] = m_aListPropertyList;
else if (rName == "style:page-layout")
m_rStyles.GetCurrentPageLayouts()[m_aName] = m_aPageLayoutPropertyList;
else if (rName == "style:master-page")
@@ -405,6 +477,8 @@ librevenge::RVNGPropertyList& XMLStyleContext::GetGraphicPropertyList()
return m_aGraphicPropertyList;
}
librevenge::RVNGPropertyList& XMLStyleContext::GetListPropertyList() { return m_aListPropertyList; }
librevenge::RVNGPropertyList& XMLStyleContext::GetPageLayoutPropertyList()
{
return m_aPageLayoutPropertyList;
@@ -38,6 +38,7 @@ public:
librevenge::RVNGPropertyList& GetRowPropertyList();
librevenge::RVNGPropertyList& GetTablePropertyList();
librevenge::RVNGPropertyList& GetGraphicPropertyList();
librevenge::RVNGPropertyList& GetListPropertyList();
librevenge::RVNGPropertyList& GetPageLayoutPropertyList();
private:
@@ -50,6 +51,7 @@ private:
librevenge::RVNGPropertyList m_aRowPropertyList;
librevenge::RVNGPropertyList m_aTablePropertyList;
librevenge::RVNGPropertyList m_aGraphicPropertyList;
librevenge::RVNGPropertyList m_aListPropertyList;
librevenge::RVNGPropertyList m_aPageLayoutPropertyList;
librevenge::RVNGPropertyList m_aMasterPagePropertyList;
XMLStylesContext& m_rStyles;
+11 -1
View File
@@ -35,6 +35,8 @@ XMLStylesContext::XMLStylesContext(XMLImport& rImport, StyleType eType)
: GetImport().GetTableStyles())
, m_rGraphicStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticGraphicStyles()
: GetImport().GetGraphicStyles())
, m_rListStyles(eType == StyleType_AUTOMATIC ? GetImport().GetAutomaticListStyles()
: GetImport().GetListStyles())
, m_rPageLayouts(GetImport().GetPageLayouts())
, m_rMasterStyles(GetImport().GetMasterStyles())
{
@@ -43,8 +45,11 @@ XMLStylesContext::XMLStylesContext(XMLImport& rImport, StyleType eType)
rtl::Reference<XMLImportContext> XMLStylesContext::CreateChildContext(
const OUString& rName, const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttribs*/)
{
if (rName == "style:style" || rName == "style:page-layout" || rName == "style:master-page")
if (rName == "style:style" || rName == "text:list-style" || rName == "style:page-layout"
|| rName == "style:master-page")
{
return new XMLStyleContext(GetImport(), *this);
}
return nullptr;
}
@@ -83,6 +88,11 @@ std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentGr
return m_rGraphicStyles;
}
std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentListStyles()
{
return m_rListStyles;
}
std::map<OUString, librevenge::RVNGPropertyList>& XMLStylesContext::GetCurrentPageLayouts()
{
return m_rPageLayouts;
@@ -42,6 +42,7 @@ public:
std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentRowStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentTableStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentGraphicStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentListStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentPageLayouts();
std::map<OUString, librevenge::RVNGPropertyList>& GetCurrentMasterStyles();
@@ -53,6 +54,7 @@ private:
std::map<OUString, librevenge::RVNGPropertyList>& m_rRowStyles;
std::map<OUString, librevenge::RVNGPropertyList>& m_rTableStyles;
std::map<OUString, librevenge::RVNGPropertyList>& m_rGraphicStyles;
std::map<OUString, librevenge::RVNGPropertyList>& m_rListStyles;
std::map<OUString, librevenge::RVNGPropertyList>& m_rPageLayouts;
std::map<OUString, librevenge::RVNGPropertyList>& m_rMasterStyles;
};
@@ -498,6 +498,11 @@ std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticGraphic
return maAutomaticGraphicStyles;
}
std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetAutomaticListStyles()
{
return maAutomaticListStyles;
}
std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetTextStyles()
{
return maTextStyles;
@@ -530,6 +535,11 @@ std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetGraphicStyles()
return maGraphicStyles;
}
std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetListStyles()
{
return maListStyles;
}
std::map<OUString, librevenge::RVNGPropertyList>& XMLImport::GetPageLayouts()
{
return maPageLayouts;
@@ -81,6 +81,8 @@ class XMLImport : public cppu::WeakImplHelper<css::xml::sax::XDocumentHandler>
std::map<OUString, librevenge::RVNGPropertyList> maTableStyles;
std::map<OUString, librevenge::RVNGPropertyList> maAutomaticGraphicStyles;
std::map<OUString, librevenge::RVNGPropertyList> maGraphicStyles;
std::map<OUString, librevenge::RVNGPropertyList> maAutomaticListStyles;
std::map<OUString, librevenge::RVNGPropertyList> maListStyles;
std::map<OUString, librevenge::RVNGPropertyList> maPageLayouts;
std::map<OUString, librevenge::RVNGPropertyList> maMasterStyles;
librevenge::RVNGPropertyListVector maCoverImages;
@@ -110,6 +112,7 @@ public:
std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticRowStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticTableStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticGraphicStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetAutomaticListStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetTextStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetParagraphStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetCellStyles();
@@ -117,6 +120,7 @@ public:
std::map<OUString, librevenge::RVNGPropertyList>& GetRowStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetTableStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetGraphicStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetListStyles();
std::map<OUString, librevenge::RVNGPropertyList>& GetPageLayouts();
std::map<OUString, librevenge::RVNGPropertyList>& GetMasterStyles();
const librevenge::RVNGPropertyListVector& GetCoverImages() const;