View Javadoc
1   /**
2    * Copyright (C) 2014-2017 Philip Helger (www.helger.com)
3    * philip[at]helger[dot]com
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *         http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package com.helger.schematron.pure.model;
18  
19  import java.util.Map;
20  
21  import javax.annotation.Nonnull;
22  import javax.annotation.Nullable;
23  import javax.annotation.concurrent.NotThreadSafe;
24  
25  import com.helger.commons.ValueEnforcer;
26  import com.helger.commons.annotation.Nonempty;
27  import com.helger.commons.annotation.ReturnsMutableCopy;
28  import com.helger.commons.collection.CollectionHelper;
29  import com.helger.commons.collection.ext.CommonsArrayList;
30  import com.helger.commons.collection.ext.CommonsLinkedHashMap;
31  import com.helger.commons.collection.ext.ICommonsList;
32  import com.helger.commons.collection.ext.ICommonsOrderedMap;
33  import com.helger.commons.string.StringHelper;
34  import com.helger.commons.string.ToStringGenerator;
35  import com.helger.schematron.CSchematron;
36  import com.helger.schematron.CSchematronXML;
37  import com.helger.schematron.pure.errorhandler.IPSErrorHandler;
38  import com.helger.xml.microdom.IMicroElement;
39  import com.helger.xml.microdom.MicroElement;
40  
41  /**
42   * A single Schematron span-element.<br>
43   * A portion of some paragraph that should be rendered in a distinct way, keyed
44   * with the class attribute.<br>
45   * An implementation is not required to make use of this element.
46   *
47   * @author Philip Helger
48   */
49  @NotThreadSafe
50  public class PSSpan implements IPSClonableElement <PSSpan>, IPSOptionalElement, IPSHasForeignElements, IPSHasTexts
51  {
52    private String m_sClass;
53    private final ICommonsList <String> m_aContent = new CommonsArrayList <> ();
54    private ICommonsOrderedMap <String, String> m_aForeignAttrs;
55    private ICommonsList <IMicroElement> m_aForeignElements;
56  
57    public PSSpan ()
58    {}
59  
60    public boolean isValid (@Nonnull final IPSErrorHandler aErrorHandler)
61    {
62      if (StringHelper.hasNoText (m_sClass))
63      {
64        aErrorHandler.error (this, "<span> has no 'class'");
65        return false;
66      }
67      if (m_aContent.isEmpty ())
68      {
69        aErrorHandler.error (this, "<span> has no content");
70        return false;
71      }
72      return true;
73    }
74  
75    public void validateCompletely (@Nonnull final IPSErrorHandler aErrorHandler)
76    {
77      if (StringHelper.hasNoText (m_sClass))
78        aErrorHandler.error (this, "<span> has no 'class'");
79      if (m_aContent.isEmpty ())
80        aErrorHandler.error (this, "<span> has no content");
81    }
82  
83    public boolean isMinimal ()
84    {
85      return true;
86    }
87  
88    public void addForeignElement (@Nonnull final IMicroElement aForeignElement)
89    {
90      ValueEnforcer.notNull (aForeignElement, "ForeignElement");
91      if (aForeignElement.hasParent ())
92        throw new IllegalArgumentException ("ForeignElement already has a parent!");
93      if (m_aForeignElements == null)
94        m_aForeignElements = new CommonsArrayList <> ();
95      m_aForeignElements.add (aForeignElement);
96    }
97  
98    public boolean hasForeignElements ()
99    {
100     return m_aForeignElements != null && m_aForeignElements.isNotEmpty ();
101   }
102 
103   @Nonnull
104   @ReturnsMutableCopy
105   public ICommonsList <IMicroElement> getAllForeignElements ()
106   {
107     return new CommonsArrayList <> (m_aForeignElements);
108   }
109 
110   public void addForeignAttribute (@Nonnull final String sAttrName, @Nonnull final String sAttrValue)
111   {
112     ValueEnforcer.notNull (sAttrName, "AttrName");
113     ValueEnforcer.notNull (sAttrValue, "AttrValue");
114     if (m_aForeignAttrs == null)
115       m_aForeignAttrs = new CommonsLinkedHashMap <> ();
116     m_aForeignAttrs.put (sAttrName, sAttrValue);
117   }
118 
119   public boolean hasForeignAttributes ()
120   {
121     return m_aForeignAttrs != null && m_aForeignAttrs.isNotEmpty ();
122   }
123 
124   @Nonnull
125   @ReturnsMutableCopy
126   public ICommonsOrderedMap <String, String> getAllForeignAttributes ()
127   {
128     return new CommonsLinkedHashMap <> (m_aForeignAttrs);
129   }
130 
131   public void setClazz (@Nullable final String sClass)
132   {
133     m_sClass = sClass;
134   }
135 
136   @Nullable
137   public String getClazz ()
138   {
139     return m_sClass;
140   }
141 
142   public void addText (@Nonnull @Nonempty final String sText)
143   {
144     ValueEnforcer.notEmpty (sText, "Text");
145     m_aContent.add (sText);
146   }
147 
148   public boolean hasAnyText ()
149   {
150     return m_aContent.isNotEmpty ();
151   }
152 
153   @Nonnull
154   @ReturnsMutableCopy
155   public ICommonsList <String> getAllTexts ()
156   {
157     return m_aContent.getClone ();
158   }
159 
160   @Nullable
161   public String getAsText ()
162   {
163     return StringHelper.getImploded (m_aContent);
164   }
165 
166   @Nonnull
167   public IMicroElement getAsMicroElement ()
168   {
169     final IMicroElement ret = new MicroElement (CSchematron.NAMESPACE_SCHEMATRON, CSchematronXML.ELEMENT_SPAN);
170     ret.setAttribute (CSchematronXML.ATTR_CLASS, m_sClass);
171     if (m_aForeignElements != null)
172       for (final IMicroElement aForeignElement : m_aForeignElements)
173         ret.appendChild (aForeignElement.getClone ());
174     for (final String sContent : m_aContent)
175       ret.appendText (sContent);
176     if (m_aForeignAttrs != null)
177       for (final Map.Entry <String, String> aEntry : m_aForeignAttrs.entrySet ())
178         ret.setAttribute (aEntry.getKey (), aEntry.getValue ());
179     return ret;
180   }
181 
182   @Nonnull
183   public PSSpan getClone ()
184   {
185     final PSSpan ret = new PSSpan ();
186     ret.setClazz (m_sClass);
187     for (final String sContent : m_aContent)
188       ret.addText (sContent);
189     if (hasForeignElements ())
190       ret.addForeignElements (m_aForeignElements);
191     if (hasForeignAttributes ())
192       ret.addForeignAttributes (m_aForeignAttrs);
193     return ret;
194   }
195 
196   @Override
197   public String toString ()
198   {
199     return new ToStringGenerator (this).appendIfNotNull ("class", m_sClass)
200                                        .appendIf ("content", m_aContent, CollectionHelper::isNotEmpty)
201                                        .appendIf ("foreignAttrs", m_aForeignAttrs, CollectionHelper::isNotEmpty)
202                                        .appendIf ("foreignElements", m_aForeignElements, CollectionHelper::isNotEmpty)
203                                        .getToString ();
204   }
205 }