View Javadoc
1   /**
2    * Copyright (C) 2014-2015 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.ArrayList;
20  import java.util.LinkedHashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import javax.annotation.Nonnull;
25  import javax.annotation.Nullable;
26  import javax.annotation.concurrent.NotThreadSafe;
27  
28  import com.helger.commons.ValueEnforcer;
29  import com.helger.commons.annotation.Nonempty;
30  import com.helger.commons.annotation.ReturnsMutableCopy;
31  import com.helger.commons.collection.CollectionHelper;
32  import com.helger.commons.microdom.IMicroElement;
33  import com.helger.commons.microdom.MicroElement;
34  import com.helger.commons.string.StringHelper;
35  import com.helger.commons.string.ToStringGenerator;
36  import com.helger.schematron.CSchematron;
37  import com.helger.schematron.CSchematronXML;
38  import com.helger.schematron.pure.errorhandler.IPSErrorHandler;
39  
40  /**
41   * A single Schematron span-element.<br>
42   * A portion of some paragraph that should be rendered in a distinct way, keyed
43   * with the class attribute.<br>
44   * An implementation is not required to make use of this element.
45   *
46   * @author Philip Helger
47   */
48  @NotThreadSafe
49  public class PSSpan implements IPSClonableElement <PSSpan>, IPSOptionalElement, IPSHasForeignElements, IPSHasTexts
50  {
51    private String m_sClass;
52    private final List <String> m_aContent = new ArrayList <String> ();
53    private Map <String, String> m_aForeignAttrs;
54    private List <IMicroElement> m_aForeignElements;
55  
56    public PSSpan ()
57    {}
58  
59    public boolean isValid (@Nonnull final IPSErrorHandler aErrorHandler)
60    {
61      if (StringHelper.hasNoText (m_sClass))
62      {
63        aErrorHandler.error (this, "<span> has no 'class'");
64        return false;
65      }
66      if (m_aContent.isEmpty ())
67      {
68        aErrorHandler.error (this, "<span> has no content");
69        return false;
70      }
71      return true;
72    }
73  
74    public void validateCompletely (@Nonnull final IPSErrorHandler aErrorHandler)
75    {
76      if (StringHelper.hasNoText (m_sClass))
77        aErrorHandler.error (this, "<span> has no 'class'");
78      if (m_aContent.isEmpty ())
79        aErrorHandler.error (this, "<span> has no content");
80    }
81  
82    public boolean isMinimal ()
83    {
84      return true;
85    }
86  
87    public void addForeignElement (@Nonnull final IMicroElement aForeignElement)
88    {
89      ValueEnforcer.notNull (aForeignElement, "ForeignElement");
90      if (aForeignElement.hasParent ())
91        throw new IllegalArgumentException ("ForeignElement already has a parent!");
92      if (m_aForeignElements == null)
93        m_aForeignElements = new ArrayList <IMicroElement> ();
94      m_aForeignElements.add (aForeignElement);
95    }
96  
97    public void addForeignElements (@Nonnull final List <IMicroElement> aForeignElements)
98    {
99      ValueEnforcer.notNull (aForeignElements, "ForeignElements");
100     for (final IMicroElement aForeignElement : aForeignElements)
101       addForeignElement (aForeignElement);
102   }
103 
104   public boolean hasForeignElements ()
105   {
106     return m_aForeignElements != null && !m_aForeignElements.isEmpty ();
107   }
108 
109   @Nonnull
110   @ReturnsMutableCopy
111   public List <IMicroElement> getAllForeignElements ()
112   {
113     return CollectionHelper.newList (m_aForeignElements);
114   }
115 
116   public void addForeignAttribute (@Nonnull final String sAttrName, @Nonnull final String sAttrValue)
117   {
118     ValueEnforcer.notNull (sAttrName, "AttrName");
119     ValueEnforcer.notNull (sAttrValue, "AttrValue");
120     if (m_aForeignAttrs == null)
121       m_aForeignAttrs = new LinkedHashMap <String, String> ();
122     m_aForeignAttrs.put (sAttrName, sAttrValue);
123   }
124 
125   public void addForeignAttributes (@Nonnull final Map <String, String> aForeignAttrs)
126   {
127     ValueEnforcer.notNull (aForeignAttrs, "ForeignAttrs");
128     for (final Map.Entry <String, String> aEntry : aForeignAttrs.entrySet ())
129       addForeignAttribute (aEntry.getKey (), aEntry.getValue ());
130   }
131 
132   public boolean hasForeignAttributes ()
133   {
134     return m_aForeignAttrs != null && !m_aForeignAttrs.isEmpty ();
135   }
136 
137   @Nonnull
138   @ReturnsMutableCopy
139   public Map <String, String> getAllForeignAttributes ()
140   {
141     return CollectionHelper.newOrderedMap (m_aForeignAttrs);
142   }
143 
144   public void setClazz (@Nullable final String sClass)
145   {
146     m_sClass = sClass;
147   }
148 
149   @Nullable
150   public String getClazz ()
151   {
152     return m_sClass;
153   }
154 
155   public void addText (@Nonnull @Nonempty final String sText)
156   {
157     ValueEnforcer.notEmpty (sText, "Text");
158     m_aContent.add (sText);
159   }
160 
161   public boolean hasAnyText ()
162   {
163     return !m_aContent.isEmpty ();
164   }
165 
166   @Nonnull
167   @ReturnsMutableCopy
168   public List <String> getAllTexts ()
169   {
170     return CollectionHelper.newList (m_aContent);
171   }
172 
173   @Nullable
174   public String getAsText ()
175   {
176     return StringHelper.getImploded (m_aContent);
177   }
178 
179   @Nonnull
180   public IMicroElement getAsMicroElement ()
181   {
182     final IMicroElement ret = new MicroElement (CSchematron.NAMESPACE_SCHEMATRON, CSchematronXML.ELEMENT_SPAN);
183     ret.setAttribute (CSchematronXML.ATTR_CLASS, m_sClass);
184     if (m_aForeignElements != null)
185       for (final IMicroElement aForeignElement : m_aForeignElements)
186         ret.appendChild (aForeignElement.getClone ());
187     for (final String sContent : m_aContent)
188       ret.appendText (sContent);
189     if (m_aForeignAttrs != null)
190       for (final Map.Entry <String, String> aEntry : m_aForeignAttrs.entrySet ())
191         ret.setAttribute (aEntry.getKey (), aEntry.getValue ());
192     return ret;
193   }
194 
195   @Nonnull
196   public PSSpan getClone ()
197   {
198     final PSSpan ret = new PSSpan ();
199     ret.setClazz (m_sClass);
200     for (final String sContent : m_aContent)
201       ret.addText (sContent);
202     if (hasForeignElements ())
203       ret.addForeignElements (m_aForeignElements);
204     if (hasForeignAttributes ())
205       ret.addForeignAttributes (m_aForeignAttrs);
206     return ret;
207   }
208 
209   @Override
210   public String toString ()
211   {
212     return new ToStringGenerator (this).appendIfNotNull ("class", m_sClass)
213                                        .appendIfNotEmpty ("content", m_aContent)
214                                        .appendIfNotEmpty ("foreignAttrs", m_aForeignAttrs)
215                                        .appendIfNotEmpty ("foreignElements", m_aForeignElements)
216                                        .toString ();
217   }
218 }