From 7a4545bd049107d5e8fba218ce5a4f99115d514d Mon Sep 17 00:00:00 2001 From: Evgeniy Luzman Date: Tue, 22 Mar 2022 10:21:48 +0200 Subject: [PATCH] Add 'style' tag processing --- FB2Library/Elements/InternalLinkItem.cs | 120 ++++++++++++++--- FB2Library/Elements/ParagraphItem.cs | 39 ++++-- FB2Library/Elements/StyleItem.cs | 171 ++++++++++++++++++++++++ 3 files changed, 297 insertions(+), 33 deletions(-) create mode 100644 FB2Library/Elements/StyleItem.cs diff --git a/FB2Library/Elements/InternalLinkItem.cs b/FB2Library/Elements/InternalLinkItem.cs index feb4700..bfbc8ff 100644 --- a/FB2Library/Elements/InternalLinkItem.cs +++ b/FB2Library/Elements/InternalLinkItem.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; +using System.Xml; using System.Xml.Linq; namespace FB2Library.Elements @@ -9,19 +9,37 @@ namespace FB2Library.Elements public class InternalLinkItem : StyleType { private readonly XNamespace lNamespace = @"http://www.w3.org/1999/xlink"; - + public string Type { get; set; } public string HRef { get; set; } - public SimpleText LinkText { get; set; } + private readonly List _linkData = new List(); + public List LinkData { get { return _linkData; } } internal const string Fb2InternalLinkElementName = "a"; public override string ToString() { - return LinkText.ToString(); + StringBuilder builder = new StringBuilder(); + builder.Append(""); + foreach (var item in _linkData) + { + builder.Append(item.ToString()); + builder.Append(" "); + } + builder.Append(""); + return builder.ToString(); } internal void Load(XElement xLink) @@ -36,22 +54,63 @@ internal void Load(XElement xLink) throw new ArgumentException("Element of wrong type passed", "xLink"); } - LinkText = null; - //if (xLink.Value != null) + if (xLink.HasElements) { - LinkText = new SimpleText(); - try - { - LinkText.Load(xLink); - } - catch (Exception) + IEnumerable childElements = xLink.Nodes(); + foreach (var element in childElements) { - LinkText = null; + if ((element.NodeType == XmlNodeType.Element) && !IsSimpleText(element)) + { + XElement xElement = (XElement)element; + if (xElement.Name.LocalName == InlineImageItem.Fb2InlineImageElementName) + { + InlineImageItem image = new InlineImageItem(); + try + { + image.Load(xElement); + _linkData.Add(image); + } + catch (Exception) + { + } + } + else if (xElement.Name.LocalName == StyleItem.StyleItemName) + { + StyleItem styleItem = new StyleItem(); + try + { + styleItem.Load(xElement); + _linkData.Add(styleItem); + } + catch (Exception) + { + } + } + } + else + { + SimpleText text = new SimpleText(); + try + { + text.Load(element); + _linkData.Add(text); + } + catch (Exception) + { + continue; + } + } } } + else if (!string.IsNullOrEmpty(xLink.Value)) + { + SimpleText text = new SimpleText(); + text.Load(xLink); + _linkData.Add(text); + } XAttribute xTypeAttr = xLink.Attribute("type"); - if ((xTypeAttr != null)&& (xTypeAttr.Value != null)) + if ((xTypeAttr != null) && (xTypeAttr.Value != null)) { Type = xTypeAttr.Value; } @@ -64,20 +123,41 @@ internal void Load(XElement xLink) } + private bool IsSimpleText(XNode element) + { + // if not element than we assume simple text + if (element.NodeType != XmlNodeType.Element) + { + return true; + } + XElement xElement = (XElement)element; + if (xElement.Name.LocalName == InternalLinkItem.Fb2InternalLinkElementName) + { + throw new ArgumentException("Schema doesn't support nested links"); + } + switch (xElement.Name.LocalName) + { + case InlineImageItem.Fb2InlineImageElementName: + case StyleItem.StyleItemName: + return false; + } + return true; + } + public XNode ToXML() { XElement xLink = new XElement(Fb2Const.fb2DefaultNamespace + Fb2InternalLinkElementName); if (!string.IsNullOrEmpty(Type)) - { - xLink.Add(new XAttribute("type",Type)); + { + xLink.Add(new XAttribute("type", Type)); } - if(!string.IsNullOrEmpty(HRef)) + if (!string.IsNullOrEmpty(HRef)) { - xLink.Add(new XAttribute(lNamespace + "href",HRef)); + xLink.Add(new XAttribute(lNamespace + "href", HRef)); } - if (LinkText != null) + foreach (StyleType childElements in _linkData) { - xLink.Add(LinkText.ToXML()); + xLink.Add(childElements.ToXML()); } return xLink; } diff --git a/FB2Library/Elements/ParagraphItem.cs b/FB2Library/Elements/ParagraphItem.cs index d14980c..d18083f 100644 --- a/FB2Library/Elements/ParagraphItem.cs +++ b/FB2Library/Elements/ParagraphItem.cs @@ -22,9 +22,9 @@ protected virtual string GetElementName() { return Fb2ParagraphElementName; } - + internal const string Fb2ParagraphElementName = "p"; - + public override string ToString() { @@ -78,24 +78,36 @@ protected void LoadData(XElement xParagraph) } catch (Exception) { - } + } } - } - else //if ( element.NodeType != XmlNodeType.Whitespace) - { - SimpleText text = new SimpleText(); + else if (xElement.Name.LocalName == StyleItem.StyleItemName) + { + StyleItem styleItem = new StyleItem(); try { - text.Load(element); - paragraphData.Add(text); + styleItem.Load(xElement); + paragraphData.Add(styleItem); } catch (Exception) { - continue; } + } + } + else //if ( element.NodeType != XmlNodeType.Whitespace) + { + SimpleText text = new SimpleText(); + try + { + text.Load(element); + paragraphData.Add(text); + } + catch (Exception) + { + continue; + } } } - + } else if (!string.IsNullOrEmpty(xParagraph.Value)) { @@ -122,7 +134,7 @@ protected void LoadData(XElement xParagraph) { Lang = xLang.Value; } - + } internal virtual void Load(XElement xParagraph) @@ -153,8 +165,9 @@ private bool IsSimpleText(XNode element) { case InternalLinkItem.Fb2InternalLinkElementName: case InlineImageItem.Fb2InlineImageElementName: + case StyleItem.StyleItemName: return false; - + } return true; } diff --git a/FB2Library/Elements/StyleItem.cs b/FB2Library/Elements/StyleItem.cs new file mode 100644 index 0000000..b3fca92 --- /dev/null +++ b/FB2Library/Elements/StyleItem.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.Xml.Linq; + +namespace FB2Library.Elements +{ + /// + /// Represents FB2 style tag + /// + public class StyleItem : IFb2TextItem, StyleType + { + internal const string StyleItemName = "style"; + + /// + /// Get/Set name of the sequence + /// + public string Name { get; set; } + /// + /// Get/Set language + /// + public string Lang { get; set; } + public List StyleData { get; set; } = new List(); + protected virtual string GetElementName() + { + return StyleItemName; + } + public override string ToString() + { + StringBuilder builder = new StringBuilder($""); + return builder.ToString(); + } + /// + /// Load element data from the node + /// + /// + public void Load(XElement xStyle) + { + if (xStyle == null) + { + throw new ArgumentNullException("style"); + } + if (xStyle.Name.LocalName != StyleItemName) + { + throw new ArgumentException(string.Format("The element is of type {0} while StyleItem accepts only {1} types", xStyle.Name.LocalName, StyleItemName)); + } + + Lang = null; + XAttribute xLang = xStyle.Attribute(XNamespace.Xml + "lang"); + if (xLang != null) + { + Lang = xLang.Value; + } + + Name = string.Empty; + XAttribute xName = xStyle.Attribute("name"); + if (xName != null && xName.Value != null) + { + Name = xName.Value; + } + + if (xStyle.HasElements) + { + IEnumerable childElements = xStyle.Nodes(); + foreach (var element in childElements) + { + if ((element.NodeType == XmlNodeType.Element) && !IsSimpleText(element)) + { + XElement xElement = (XElement)element; + if (xElement.Name.LocalName == InlineImageItem.Fb2InlineImageElementName) + { + InlineImageItem image = new InlineImageItem(); + try + { + image.Load(xElement); + StyleData.Add(image); + } + catch (Exception) + { + } + } + else if (xElement.Name.LocalName == InternalLinkItem.Fb2InternalLinkElementName) + { + InternalLinkItem linkItem = new InternalLinkItem(); + try + { + linkItem.Load(xElement); + StyleData.Add(linkItem); + } + catch (Exception) + { + } + } + else if (xElement.Name.LocalName == StyleItemName) + { + StyleItem styleItem = new StyleItem(); + try + { + styleItem.Load(xElement); + StyleData.Add(styleItem); + } + catch (Exception) + { + } + } + } + else + { + SimpleText text = new SimpleText(); + try + { + text.Load(element); + StyleData.Add(text); + } + catch (Exception) + { + } + } + } + + } + else if (!string.IsNullOrEmpty(xStyle.Value)) + { + SimpleText text = new SimpleText(); + text.Load(xStyle); + StyleData.Add(text); + } + } + private bool IsSimpleText(XNode element) + { + // if not element than we assume simple text + if (element.NodeType != XmlNodeType.Element) + { + return true; + } + XElement xElement = (XElement)element; + switch (xElement.Name.LocalName) + { + case InternalLinkItem.Fb2InternalLinkElementName: + case InlineImageItem.Fb2InlineImageElementName: + case StyleItem.StyleItemName: + return false; + } + return true; + } + public XNode ToXML() + { + if (Name == null || string.IsNullOrEmpty(Name)) + { + throw new Exception("Name attribute is required by standard"); + } + XElement xStyle = new XElement(Fb2Const.fb2DefaultNamespace + StyleItemName, new XAttribute("name", Name)); + if (!string.IsNullOrEmpty(Lang)) + { + xStyle.Add(new XAttribute(XNamespace.Xml + "lang", Lang)); + } + foreach (StyleType childElements in StyleData) + { + xStyle.Add(childElements.ToXML()); + } + return xStyle; + } + } +}