1 // Copyright 2017 The PDFium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "core/fxcrt/xml/cfx_xmlelement.h" 8 9 #include "core/fxcrt/fx_extension.h" 10 #include "core/fxcrt/xml/cfx_xmlchardata.h" 11 #include "core/fxcrt/xml/cfx_xmldocument.h" 12 #include "core/fxcrt/xml/cfx_xmltext.h" 13 #include "third_party/base/check.h" 14 CFX_XMLElement(const WideString & wsTag)15CFX_XMLElement::CFX_XMLElement(const WideString& wsTag) : name_(wsTag) { 16 DCHECK(!name_.IsEmpty()); 17 } 18 19 CFX_XMLElement::~CFX_XMLElement() = default; 20 GetType() const21CFX_XMLNode::Type CFX_XMLElement::GetType() const { 22 return Type::kElement; 23 } 24 Clone(CFX_XMLDocument * doc)25CFX_XMLNode* CFX_XMLElement::Clone(CFX_XMLDocument* doc) { 26 auto* node = doc->CreateNode<CFX_XMLElement>(name_); 27 node->attrs_ = attrs_; 28 29 // TODO(dsinclair): This clone is wrong. It doesn't clone all child nodes just 30 // text nodes? 31 for (CFX_XMLNode* pChild = GetFirstChild(); pChild; 32 pChild = pChild->GetNextSibling()) { 33 if (pChild->GetType() == Type::kText) 34 node->AppendLastChild(pChild->Clone(doc)); 35 } 36 return node; 37 } 38 GetLocalTagName() const39WideString CFX_XMLElement::GetLocalTagName() const { 40 auto pos = name_.Find(L':'); 41 return pos.has_value() ? name_.Last(name_.GetLength() - pos.value() - 1) 42 : name_; 43 } 44 GetNamespacePrefix() const45WideString CFX_XMLElement::GetNamespacePrefix() const { 46 auto pos = name_.Find(L':'); 47 return pos.has_value() ? name_.First(pos.value()) : WideString(); 48 } 49 GetNamespaceURI() const50WideString CFX_XMLElement::GetNamespaceURI() const { 51 WideString attr(L"xmlns"); 52 WideString wsPrefix = GetNamespacePrefix(); 53 if (!wsPrefix.IsEmpty()) { 54 attr += L":"; 55 attr += wsPrefix; 56 } 57 const CFX_XMLNode* pNode = this; 58 while (pNode && pNode->GetType() == Type::kElement) { 59 auto* pElement = static_cast<const CFX_XMLElement*>(pNode); 60 if (!pElement->HasAttribute(attr)) { 61 pNode = pNode->GetParent(); 62 continue; 63 } 64 return pElement->GetAttribute(attr); 65 } 66 return WideString(); 67 } 68 GetTextData() const69WideString CFX_XMLElement::GetTextData() const { 70 WideString buffer; 71 for (CFX_XMLNode* pChild = GetFirstChild(); pChild; 72 pChild = pChild->GetNextSibling()) { 73 CFX_XMLText* pText = ToXMLText(pChild); 74 if (pText) 75 buffer += pText->GetText(); 76 } 77 return buffer; 78 } 79 Save(const RetainPtr<IFX_RetainableWriteStream> & pXMLStream)80void CFX_XMLElement::Save( 81 const RetainPtr<IFX_RetainableWriteStream>& pXMLStream) { 82 ByteString bsNameEncoded = name_.ToUTF8(); 83 84 pXMLStream->WriteString("<"); 85 pXMLStream->WriteString(bsNameEncoded.AsStringView()); 86 87 for (const auto& it : attrs_) { 88 // Note, the space between attributes is added by AttributeToString which 89 // writes a blank as the first character. 90 pXMLStream->WriteString( 91 AttributeToString(it.first, it.second).ToUTF8().AsStringView()); 92 } 93 94 if (!GetFirstChild()) { 95 pXMLStream->WriteString(" />\n"); 96 return; 97 } 98 99 pXMLStream->WriteString(">\n"); 100 101 for (CFX_XMLNode* pChild = GetFirstChild(); pChild; 102 pChild = pChild->GetNextSibling()) { 103 pChild->Save(pXMLStream); 104 } 105 pXMLStream->WriteString("</"); 106 pXMLStream->WriteString(bsNameEncoded.AsStringView()); 107 pXMLStream->WriteString(">\n"); 108 } 109 GetFirstChildNamed(WideStringView name) const110CFX_XMLElement* CFX_XMLElement::GetFirstChildNamed(WideStringView name) const { 111 return GetNthChildNamed(name, 0); 112 } 113 GetNthChildNamed(WideStringView name,size_t idx) const114CFX_XMLElement* CFX_XMLElement::GetNthChildNamed(WideStringView name, 115 size_t idx) const { 116 for (auto* child = GetFirstChild(); child; child = child->GetNextSibling()) { 117 CFX_XMLElement* elem = ToXMLElement(child); 118 if (!elem || elem->name_ != name) 119 continue; 120 if (idx == 0) 121 return elem; 122 123 --idx; 124 } 125 return nullptr; 126 } 127 HasAttribute(const WideString & name) const128bool CFX_XMLElement::HasAttribute(const WideString& name) const { 129 return attrs_.find(name) != attrs_.end(); 130 } 131 GetAttribute(const WideString & name) const132WideString CFX_XMLElement::GetAttribute(const WideString& name) const { 133 auto it = attrs_.find(name); 134 return it != attrs_.end() ? it->second : WideString(); 135 } 136 SetAttribute(const WideString & name,const WideString & value)137void CFX_XMLElement::SetAttribute(const WideString& name, 138 const WideString& value) { 139 attrs_[name] = value; 140 } 141 RemoveAttribute(const WideString & name)142void CFX_XMLElement::RemoveAttribute(const WideString& name) { 143 attrs_.erase(name); 144 } 145 AttributeToString(const WideString & name,const WideString & value)146WideString CFX_XMLElement::AttributeToString(const WideString& name, 147 const WideString& value) { 148 WideString ret = L" "; 149 ret += name; 150 ret += L"=\""; 151 ret += value.EncodeEntities(); 152 ret += L"\""; 153 return ret; 154 } 155