All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.xml.microdom.util.MicroHelper Maven / Gradle / Ivy

There is a newer version: 11.1.8
Show newest version
/*
 * Copyright (C) 2014-2023 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.xml.microdom.util;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.xml.XMLConstants;

import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.ProcessingInstruction;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.PresentForCodeCoverage;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.collection.ArrayHelper;
import com.helger.xml.XMLHelper;
import com.helger.xml.microdom.IMicroContainer;
import com.helger.xml.microdom.IMicroDocument;
import com.helger.xml.microdom.IMicroElement;
import com.helger.xml.microdom.IMicroNode;
import com.helger.xml.microdom.MicroCDATA;
import com.helger.xml.microdom.MicroComment;
import com.helger.xml.microdom.MicroContainer;
import com.helger.xml.microdom.MicroDocument;
import com.helger.xml.microdom.MicroDocumentType;
import com.helger.xml.microdom.MicroElement;
import com.helger.xml.microdom.MicroEntityReference;
import com.helger.xml.microdom.MicroProcessingInstruction;
import com.helger.xml.microdom.MicroText;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
 * Some utility methods on micro nodes.
 *
 * @author Philip Helger
 */
@Immutable
public final class MicroHelper
{
  @PresentForCodeCoverage
  private static final MicroHelper INSTANCE = new MicroHelper ();

  private MicroHelper ()
  {}

  @Nonnull
  public static IMicroNode append (@Nonnull final IMicroNode aSrcNode, @Nullable final Object aChild)
  {
    ValueEnforcer.notNull (aSrcNode, "SrcNode");

    if (aChild != null)
      if (aChild instanceof IMicroNode)
      {
        // directly append Node
        aSrcNode.appendChild ((IMicroNode) aChild);
      }
      else
        if (aChild instanceof String)
        {
          // append a string node
          aSrcNode.appendText ((String) aChild);
        }
        else
          if (aChild instanceof Iterable )
          {
            // it's a nested collection
            for (final Object aSubChild : (Iterable ) aChild)
              append (aSrcNode, aSubChild);
          }
          else
            if (ArrayHelper.isArray (aChild))
            {
              // it's a nested collection
              for (final Object aSubChild : (Object []) aChild)
                append (aSrcNode, aSubChild);
            }
            else
            {
              // unsupported type
              throw new IllegalArgumentException ("Passed object cannot be appended to an IMicroNode (type=" +
                                                  aChild.getClass ().getName () +
                                                  ".");
            }
    return aSrcNode;
  }

  /**
   * Get the path of the given node, up to the root element.
   *
   * @param aNode
   *        The node to get the path from. May be null.
   * @param sSep
   *        The separator to be put between each level. For XPath e.g. use "/"
   * @return A non-null string. If the passed node is
   *         null, the return value is an empty string.
   */
  @Nonnull
  @SuppressFBWarnings ("IL_INFINITE_LOOP")
  public static String getPath (@Nullable final IMicroNode aNode, @Nonnull final String sSep)
  {
    ValueEnforcer.notNull (sSep, "Separator");

    final StringBuilder aSB = new StringBuilder ();
    IMicroNode aCurrentNode = aNode;
    while (aCurrentNode != null)
    {
      if (aSB.length () > 0)
        aSB.insert (0, sSep);
      aSB.insert (0, aCurrentNode.getNodeName ());
      aCurrentNode = aCurrentNode.getParent ();
    }
    return aSB.toString ();
  }

  /**
   * Get the tag name of the passed documents root element.
   *
   * @param aDoc
   *        The document to be evaluated. May be null.
   * @return null if the passed document was null or
   *         if no document element is present. The tag name otherwise.
   */
  @Nullable
  public static String getDocumentRootElementTagName (@Nullable final IMicroDocument aDoc)
  {
    if (aDoc != null)
    {
      final IMicroElement eRoot = aDoc.getDocumentElement ();
      if (eRoot != null)
        return eRoot.getTagName ();
    }
    return null;
  }

  @Nonnull
  public static IMicroNode convertToMicroNode (@Nonnull final Node aNode)
  {
    ValueEnforcer.notNull (aNode, "Node");

    final IMicroNode ret;
    final short nNodeType = aNode.getNodeType ();
    switch (nNodeType)
    {
      case Node.DOCUMENT_NODE:
      {
        ret = new MicroDocument ();
        break;
      }
      case Node.DOCUMENT_TYPE_NODE:
      {
        final DocumentType aDT = (DocumentType) aNode;
        // inline DTDs are not supported yet
        // aDT.getEntities ();
        ret = new MicroDocumentType (aDT.getName (), aDT.getPublicId (), aDT.getSystemId ());
        break;
      }
      case Node.ELEMENT_NODE:
      {
        final Element aElement = (Element) aNode;
        final String sNamespaceURI = aElement.getNamespaceURI ();
        final IMicroElement eElement = sNamespaceURI != null ? new MicroElement (sNamespaceURI, aElement.getLocalName ())
                                                             : new MicroElement (aElement.getTagName ());
        XMLHelper.forAllAttributes (aElement, aAttr -> {
          final String sAttrNamespaceURI = aAttr.getNamespaceURI ();
          if (sAttrNamespaceURI != null)
          {
            // Ignore all "xmlns" attributes (special namespace URI!)
            if (!XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals (sAttrNamespaceURI))
              eElement.setAttribute (sAttrNamespaceURI, aAttr.getLocalName (), aAttr.getValue ());
          }
          else
            eElement.setAttribute (aAttr.getName (), aAttr.getValue ());
        });
        ret = eElement;
        break;
      }
      case Node.CDATA_SECTION_NODE:
        ret = new MicroCDATA (aNode.getNodeValue ());
        break;
      case Node.TEXT_NODE:
        ret = new MicroText (aNode.getNodeValue ());
        break;
      case Node.COMMENT_NODE:
        ret = new MicroComment (aNode.getNodeValue ());
        break;
      case Node.ENTITY_REFERENCE_NODE:
        ret = new MicroEntityReference (aNode.getNodeValue ());
        break;
      case Node.PROCESSING_INSTRUCTION_NODE:
        final ProcessingInstruction aPI = (ProcessingInstruction) aNode;
        ret = new MicroProcessingInstruction (aPI.getTarget (), aPI.getData ());
        break;
      case Node.ATTRIBUTE_NODE:
        throw new IllegalArgumentException ("Unknown/unsupported node type: ATTRIBUTE_NODE");
      case Node.ENTITY_NODE:
        throw new IllegalArgumentException ("Unknown/unsupported node type: ENTITY_NODE");
      case Node.DOCUMENT_FRAGMENT_NODE:
        throw new IllegalArgumentException ("Unknown/unsupported node type: DOCUMENT_FRAGMENT_NODE");
      case Node.NOTATION_NODE:
        throw new IllegalArgumentException ("Unknown/unsupported node type: NOTATION_NODE");
      default:
        throw new IllegalArgumentException ("Unknown/unsupported node type: " + nNodeType);
    }

    // handle children recursively (works for different node types)
    XMLHelper.iterateChildren (aNode, x -> ret.appendChild (convertToMicroNode (x)));

    return ret;
  }

  /**
   * Helper method to extract the text content of the child element denoted by
   * the parameter sChildElementName of the passed parent element.
   *
   * @param eParentElement
   *        The parent element to use. May not be null.
   * @param sChildElementName
   *        The name of the child element who's text content is to be extracted.
   * @return null if the child element does not exist or the child
   *         element does not contain any text.
   */
  @Nullable
  public static String getChildTextContent (@Nonnull final IMicroElement eParentElement, @Nonnull final String sChildElementName)
  {
    final IMicroElement eChildElement = eParentElement.getFirstChildElement (sChildElementName);
    return eChildElement != null ? eChildElement.getTextContent () : null;
  }

  /**
   * Helper method to extract the text content of the child element denoted by
   * the parameter sChildElementName of the passed parent element. After
   * concatenation, all leading and trailing spaces are removed.
   *
   * @param eParentElement
   *        The parent element to use. May not be null.
   * @param sChildElementName
   *        The name of the child element who's text content is to be extracted.
   * @return null if the child element does not exist or the child
   *         element does not contain any text.
   */
  @Nullable
  public static String getChildTextContentTrimmed (@Nonnull final IMicroElement eParentElement, @Nonnull final String sChildElementName)
  {
    final IMicroElement eChildElement = eParentElement.getFirstChildElement (sChildElementName);
    return eChildElement != null ? eChildElement.getTextContentTrimmed () : null;
  }

  /**
   * Helper method to extract the text content of the child element denoted by
   * the parameter sChildElementName of the passed parent element. The read text
   * content is converted via the
   * {@link com.helger.commons.typeconvert.TypeConverter} to the desired
   * destination type.
   *
   * @param 
   *        Destination type
   * @param eParentElement
   *        The parent element to use. May not be null.
   * @param sChildElementName
   *        The name of the child element who's text content is to be extracted.
   * @param aDstClass
   *        The destination class. May not be null.
   * @return null if the child element does not exist or the child
   *         element does not contain any text.
   */
  @Nullable
  public static  DSTTYPE getChildTextContentWithConversion (@Nonnull final IMicroElement eParentElement,
                                                                     @Nonnull final String sChildElementName,
                                                                     @Nonnull final Class  aDstClass)
  {
    final IMicroElement eChildElement = eParentElement.getFirstChildElement (sChildElementName);
    return eChildElement != null ? eChildElement.getTextContentWithConversion (aDstClass) : null;
  }

  /**
   * Helper method to extract the text content of the child element denoted by
   * the parameters sNamespaceURI and sChildElementName of the passed parent
   * element.
   *
   * @param eParentElement
   *        The parent element to use. May not be null.
   * @param sNamespaceURI
   *        The expected namespace URI of the element.
   * @param sChildElementName
   *        The name of the child element who's text content is to be extracted.
   * @return null if the child element does not exist or the child
   *         element does not contain any text.
   */
  @Nullable
  public static String getChildTextContent (@Nonnull final IMicroElement eParentElement,
                                            @Nonnull final String sNamespaceURI,
                                            @Nonnull final String sChildElementName)
  {
    final IMicroElement eChildElement = eParentElement.getFirstChildElement (sNamespaceURI, sChildElementName);
    return eChildElement != null ? eChildElement.getTextContent () : null;
  }

  /**
   * Helper method to extract the text content of the child element denoted by
   * the parameters sNamespaceURI and sChildElementName of the passed parent
   * element. After concatenation, all leading and trailing spaces are removed.
   *
   * @param eParentElement
   *        The parent element to use. May not be null.
   * @param sNamespaceURI
   *        The expected namespace URI of the element.
   * @param sChildElementName
   *        The name of the child element who's text content is to be extracted.
   * @return null if the child element does not exist or the child
   *         element does not contain any text.
   */
  @Nullable
  public static String getChildTextContentTrimmed (@Nonnull final IMicroElement eParentElement,
                                                   @Nonnull final String sNamespaceURI,
                                                   @Nonnull final String sChildElementName)
  {
    final IMicroElement eChildElement = eParentElement.getFirstChildElement (sNamespaceURI, sChildElementName);
    return eChildElement != null ? eChildElement.getTextContentTrimmed () : null;
  }

  /**
   * Helper method to extract the text content of the child element denoted by
   * the parameters sNamespaceURI and sChildElementName of the passed parent
   * element. The read text content is converted via the
   * {@link com.helger.commons.typeconvert.TypeConverter} to the desired
   * destination type.
   *
   * @param 
   *        Destination type
   * @param eParentElement
   *        The parent element to use. May not be null.
   * @param sNamespaceURI
   *        The expected namespace URI of the element.
   * @param sChildElementName
   *        The name of the child element who's text content is to be extracted.
   * @param aDstClass
   *        The destination class. May not be null.
   * @return null if the child element does not exist or the child
   *         element does not contain any text.
   */
  @Nullable
  public static  DSTTYPE getChildTextContentWithConversion (@Nonnull final IMicroElement eParentElement,
                                                                     @Nonnull final String sNamespaceURI,
                                                                     @Nonnull final String sChildElementName,
                                                                     @Nonnull final Class  aDstClass)
  {
    final IMicroElement eChildElement = eParentElement.getFirstChildElement (sNamespaceURI, sChildElementName);
    return eChildElement != null ? eChildElement.getTextContentWithConversion (aDstClass) : null;
  }

  /**
   * Create a micro container with all children of the passed node. If the
   * passed node has no children, an empty object is returned. The resulting
   * container contains a clone of each child node so that the original objects
   * is not modified.
   *
   * @param aParent
   *        The parent node to get the children from. May not be
   *        null.
   * @return The micro container and never null but maybe empty.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static IMicroContainer getAllChildrenAsContainer (@Nonnull final IMicroNode aParent)
  {
    final IMicroContainer ret = new MicroContainer ();
    aParent.forAllChildren (aChildNode -> ret.appendChild (aChildNode.getClone ()));
    return ret;
  }

  /**
   * Create a micro container with all children of the passed node. If the
   * passed node has no children, an empty object is returned. The resulting
   * container contains the original child nodes so that they no longer belong
   * to the original object. THis implies that the original object is modified!
   *
   * @param aParent
   *        The parent node to get the children from. May not be
   *        null.
   * @return The micro container and never null but maybe empty.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static IMicroContainer getAllOriginalChildrenAsContainer (@Nonnull final IMicroNode aParent)
  {
    final IMicroContainer ret = new MicroContainer ();
    aParent.forAllChildren (aChildNode -> ret.appendChild (aChildNode.detachFromParent ()));
    return ret;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy